<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://ouroboros.rocks/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dimitri</id>
	<title>Ouroboros - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://ouroboros.rocks/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dimitri"/>
	<link rel="alternate" type="text/html" href="https://ouroboros.rocks/wiki/Special:Contributions/Dimitri"/>
	<updated>2026-06-02T12:16:14Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1925</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1925"/>
		<updated>2026-05-18T16:11:20Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 8. Retransmission */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields are in network byte order. DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet. The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it. It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&lt;br /&gt;
Encoding.  When a duplicate is observed the receiver arms a&lt;br /&gt;
single-slot pending report (&amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;dsack_valid&amp;lt;/code&amp;gt;,&lt;br /&gt;
latest-wins across multiple arms before the next emit).  On the&lt;br /&gt;
next outbound SACK the receiver prepends &amp;lt;code&amp;gt;block[0] = [dsack_seqno,&lt;br /&gt;
dsack_seqno + 1)&amp;lt;/code&amp;gt; - always a one-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range - and clears the&lt;br /&gt;
flag.  The three arm sites are listed in [[#10. Cumulative + selective ACK|Section 10]]; case-1 sites&lt;br /&gt;
yield &amp;lt;code&amp;gt;dsack_seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt; (the next &amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;), and the&lt;br /&gt;
case-2 site (&amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict) yields &amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; in&lt;br /&gt;
&amp;lt;code&amp;gt;[rcv_cr.lwe, rcv_cr.rwe)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Detection.  The sender classifies &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; by its relation to&lt;br /&gt;
&amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, pci.ackno)&amp;lt;/code&amp;gt; AND &amp;lt;code&amp;gt;pci.ackno - blocks[0].start &amp;amp;lt;= MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  The lag bound rejects stale or spoofed reports beyond one receive window.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range (with at least one endpoint differing) of some &amp;lt;code&amp;gt;blocks[i&amp;amp;gt;0]&amp;lt;/code&amp;gt; - i.e. the same packet&#039;s remaining SACK blocks already describe the duplicated &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; as received.&lt;br /&gt;
&lt;br /&gt;
On detect, the sender:&lt;br /&gt;
&lt;br /&gt;
* bumps &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; by 1, capped at &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; (= 20), per RFC 8985 sec. 6.2 step 4;&lt;br /&gt;
* snapshots &amp;lt;code&amp;gt;dsack_lwe_snap = snd_cr.lwe&amp;lt;/code&amp;gt;, resetting the 16-cum-ACK halving counter so the multiplier doesn&#039;t decay while D-SACK evidence is still arriving;&lt;br /&gt;
* excludes &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; from the gap-marking loop (&amp;lt;code&amp;gt;n_real = n - 1&amp;lt;/code&amp;gt;), so a D-SACK alone never enters NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks count as gaps.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; halving cadence (once per 16 cumulatively-ACK&#039;d&lt;br /&gt;
seqnos since the most-recent D-SACK arrival or halve event) and&lt;br /&gt;
the reset-to-1 on a HoL RTO fire are both per the same RFC 8985&lt;br /&gt;
clause.  The clamp-and-skip path in the regular SACK-mark loop is&lt;br /&gt;
incidentally idempotent on any leftover case-1 or case-2 block&lt;br /&gt;
(&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; and the inner loop&lt;br /&gt;
skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;; case-2 re-NULLs slots already marked&lt;br /&gt;
received by later blocks), so block[0] is harmless even when fed&lt;br /&gt;
to the loop.&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below). Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement (no impact on receiver state). On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST NOT be emitted after &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed.&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity. Ouroboros flow allocation runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys. This is finer-grained than QUIC (per-connection, RFC 9001, where one handshake covers all multiplexed streams) and finer-grained than typical IPsec deployment (per-host-pair Security Associations, SAs). Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH + post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection. The AEAD layer itself does NOT carry an explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec. 3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then discarded either as a duplicate (still inside the receive window or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has advanced since the original packet was delivered. RAW (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore no replay protection at the AEAD layer either; deployments that need replay rejection on RAW flows SHOULD use SVC_MESSAGE.&lt;br /&gt;
&lt;br /&gt;
Layering. The AEAD wrap sits below FRCP on the data path, so RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity + confidentiality scope as FRCP-engaged flows - whatever the process and FRCP (if any) put on the wire is what the AEAD authenticates. No DTLS-equivalent layering is required for confidentiality and integrity; replay protection above AEAD is a separate concern as noted above.&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1924</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1924"/>
		<updated>2026-05-18T16:06:09Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 4. Sequence-number rotation (DRF) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields are in network byte order. DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet. The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it. It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&lt;br /&gt;
Encoding.  When a duplicate is observed the receiver arms a&lt;br /&gt;
single-slot pending report (&amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;dsack_valid&amp;lt;/code&amp;gt;,&lt;br /&gt;
latest-wins across multiple arms before the next emit).  On the&lt;br /&gt;
next outbound SACK the receiver prepends &amp;lt;code&amp;gt;block[0] = [dsack_seqno,&lt;br /&gt;
dsack_seqno + 1)&amp;lt;/code&amp;gt; - always a one-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range - and clears the&lt;br /&gt;
flag.  The three arm sites are listed in [[#10. Cumulative + selective ACK|Section 10]]; case-1 sites&lt;br /&gt;
yield &amp;lt;code&amp;gt;dsack_seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt; (the next &amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;), and the&lt;br /&gt;
case-2 site (&amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict) yields &amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; in&lt;br /&gt;
&amp;lt;code&amp;gt;[rcv_cr.lwe, rcv_cr.rwe)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Detection.  The sender classifies &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; by its relation to&lt;br /&gt;
&amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, pci.ackno)&amp;lt;/code&amp;gt; AND &amp;lt;code&amp;gt;pci.ackno - blocks[0].start &amp;amp;lt;= MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  The lag bound rejects stale or spoofed reports beyond one receive window.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range (with at least one endpoint differing) of some &amp;lt;code&amp;gt;blocks[i&amp;amp;gt;0]&amp;lt;/code&amp;gt; - i.e. the same packet&#039;s remaining SACK blocks already describe the duplicated &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; as received.&lt;br /&gt;
&lt;br /&gt;
On detect, the sender:&lt;br /&gt;
&lt;br /&gt;
* bumps &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; by 1, capped at &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; (= 20), per RFC 8985 sec. 6.2 step 4;&lt;br /&gt;
* snapshots &amp;lt;code&amp;gt;dsack_lwe_snap = snd_cr.lwe&amp;lt;/code&amp;gt;, resetting the 16-cum-ACK halving counter so the multiplier doesn&#039;t decay while D-SACK evidence is still arriving;&lt;br /&gt;
* excludes &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; from the gap-marking loop (&amp;lt;code&amp;gt;n_real = n - 1&amp;lt;/code&amp;gt;), so a D-SACK alone never enters NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks count as gaps.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; halving cadence (once per 16 cumulatively-ACK&#039;d&lt;br /&gt;
seqnos since the most-recent D-SACK arrival or halve event) and&lt;br /&gt;
the reset-to-1 on a HoL RTO fire are both per the same RFC 8985&lt;br /&gt;
clause.  The clamp-and-skip path in the regular SACK-mark loop is&lt;br /&gt;
incidentally idempotent on any leftover case-1 or case-2 block&lt;br /&gt;
(&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; and the inner loop&lt;br /&gt;
skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;; case-2 re-NULLs slots already marked&lt;br /&gt;
received by later blocks), so block[0] is harmless even when fed&lt;br /&gt;
to the loop.&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below). Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement (no impact on receiver state). On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity. Ouroboros flow allocation runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys. This is finer-grained than QUIC (per-connection, RFC 9001, where one handshake covers all multiplexed streams) and finer-grained than typical IPsec deployment (per-host-pair Security Associations, SAs). Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH + post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection. The AEAD layer itself does NOT carry an explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec. 3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then discarded either as a duplicate (still inside the receive window or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has advanced since the original packet was delivered. RAW (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore no replay protection at the AEAD layer either; deployments that need replay rejection on RAW flows SHOULD use SVC_MESSAGE.&lt;br /&gt;
&lt;br /&gt;
Layering. The AEAD wrap sits below FRCP on the data path, so RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity + confidentiality scope as FRCP-engaged flows - whatever the process and FRCP (if any) put on the wire is what the AEAD authenticates. No DTLS-equivalent layering is required for confidentiality and integrity; replay protection above AEAD is a separate concern as noted above.&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1923</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1923"/>
		<updated>2026-05-18T01:06:47Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 1.1. PCI header */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields are in network byte order. DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet. The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it. It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&lt;br /&gt;
Encoding.  When a duplicate is observed the receiver arms a&lt;br /&gt;
single-slot pending report (&amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;dsack_valid&amp;lt;/code&amp;gt;,&lt;br /&gt;
latest-wins across multiple arms before the next emit).  On the&lt;br /&gt;
next outbound SACK the receiver prepends &amp;lt;code&amp;gt;block[0] = [dsack_seqno,&lt;br /&gt;
dsack_seqno + 1)&amp;lt;/code&amp;gt; - always a one-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range - and clears the&lt;br /&gt;
flag.  The three arm sites are listed in [[#10. Cumulative + selective ACK|Section 10]]; case-1 sites&lt;br /&gt;
yield &amp;lt;code&amp;gt;dsack_seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt; (the next &amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;), and the&lt;br /&gt;
case-2 site (&amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict) yields &amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; in&lt;br /&gt;
&amp;lt;code&amp;gt;[rcv_cr.lwe, rcv_cr.rwe)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Detection.  The sender classifies &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; by its relation to&lt;br /&gt;
&amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, pci.ackno)&amp;lt;/code&amp;gt; AND &amp;lt;code&amp;gt;pci.ackno - blocks[0].start &amp;amp;lt;= MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  The lag bound rejects stale or spoofed reports beyond one receive window.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range (with at least one endpoint differing) of some &amp;lt;code&amp;gt;blocks[i&amp;amp;gt;0]&amp;lt;/code&amp;gt; - i.e. the same packet&#039;s remaining SACK blocks already describe the duplicated &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; as received.&lt;br /&gt;
&lt;br /&gt;
On detect, the sender:&lt;br /&gt;
&lt;br /&gt;
* bumps &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; by 1, capped at &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; (= 20), per RFC 8985 sec. 6.2 step 4;&lt;br /&gt;
* snapshots &amp;lt;code&amp;gt;dsack_lwe_snap = snd_cr.lwe&amp;lt;/code&amp;gt;, resetting the 16-cum-ACK halving counter so the multiplier doesn&#039;t decay while D-SACK evidence is still arriving;&lt;br /&gt;
* excludes &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; from the gap-marking loop (&amp;lt;code&amp;gt;n_real = n - 1&amp;lt;/code&amp;gt;), so a D-SACK alone never enters NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks count as gaps.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; halving cadence (once per 16 cumulatively-ACK&#039;d&lt;br /&gt;
seqnos since the most-recent D-SACK arrival or halve event) and&lt;br /&gt;
the reset-to-1 on a HoL RTO fire are both per the same RFC 8985&lt;br /&gt;
clause.  The clamp-and-skip path in the regular SACK-mark loop is&lt;br /&gt;
incidentally idempotent on any leftover case-1 or case-2 block&lt;br /&gt;
(&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; and the inner loop&lt;br /&gt;
skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;; case-2 re-NULLs slots already marked&lt;br /&gt;
received by later blocks), so block[0] is harmless even when fed&lt;br /&gt;
to the loop.&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity. Ouroboros flow allocation runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys. This is finer-grained than QUIC (per-connection, RFC 9001, where one handshake covers all multiplexed streams) and finer-grained than typical IPsec deployment (per-host-pair Security Associations, SAs). Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH + post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection. The AEAD layer itself does NOT carry an explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec. 3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then discarded either as a duplicate (still inside the receive window or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has advanced since the original packet was delivered. RAW (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore no replay protection at the AEAD layer either; deployments that need replay rejection on RAW flows SHOULD use SVC_MESSAGE.&lt;br /&gt;
&lt;br /&gt;
Layering. The AEAD wrap sits below FRCP on the data path, so RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity + confidentiality scope as FRCP-engaged flows - whatever the process and FRCP (if any) put on the wire is what the AEAD authenticates. No DTLS-equivalent layering is required for confidentiality and integrity; replay protection above AEAD is a separate concern as noted above.&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1922</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1922"/>
		<updated>2026-05-18T01:04:52Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 1.1. PCI header */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields are in network byte order. DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet; the trailer is written as a raw &amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; (the same convention as &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;: opaque on the wire as long as both peers run compatible builds).  The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it.  It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&lt;br /&gt;
Encoding.  When a duplicate is observed the receiver arms a&lt;br /&gt;
single-slot pending report (&amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;dsack_valid&amp;lt;/code&amp;gt;,&lt;br /&gt;
latest-wins across multiple arms before the next emit).  On the&lt;br /&gt;
next outbound SACK the receiver prepends &amp;lt;code&amp;gt;block[0] = [dsack_seqno,&lt;br /&gt;
dsack_seqno + 1)&amp;lt;/code&amp;gt; - always a one-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range - and clears the&lt;br /&gt;
flag.  The three arm sites are listed in [[#10. Cumulative + selective ACK|Section 10]]; case-1 sites&lt;br /&gt;
yield &amp;lt;code&amp;gt;dsack_seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt; (the next &amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;), and the&lt;br /&gt;
case-2 site (&amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict) yields &amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; in&lt;br /&gt;
&amp;lt;code&amp;gt;[rcv_cr.lwe, rcv_cr.rwe)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Detection.  The sender classifies &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; by its relation to&lt;br /&gt;
&amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, pci.ackno)&amp;lt;/code&amp;gt; AND &amp;lt;code&amp;gt;pci.ackno - blocks[0].start &amp;amp;lt;= MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  The lag bound rejects stale or spoofed reports beyond one receive window.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range (with at least one endpoint differing) of some &amp;lt;code&amp;gt;blocks[i&amp;amp;gt;0]&amp;lt;/code&amp;gt; - i.e. the same packet&#039;s remaining SACK blocks already describe the duplicated &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; as received.&lt;br /&gt;
&lt;br /&gt;
On detect, the sender:&lt;br /&gt;
&lt;br /&gt;
* bumps &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; by 1, capped at &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; (= 20), per RFC 8985 sec. 6.2 step 4;&lt;br /&gt;
* snapshots &amp;lt;code&amp;gt;dsack_lwe_snap = snd_cr.lwe&amp;lt;/code&amp;gt;, resetting the 16-cum-ACK halving counter so the multiplier doesn&#039;t decay while D-SACK evidence is still arriving;&lt;br /&gt;
* excludes &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; from the gap-marking loop (&amp;lt;code&amp;gt;n_real = n - 1&amp;lt;/code&amp;gt;), so a D-SACK alone never enters NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks count as gaps.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; halving cadence (once per 16 cumulatively-ACK&#039;d&lt;br /&gt;
seqnos since the most-recent D-SACK arrival or halve event) and&lt;br /&gt;
the reset-to-1 on a HoL RTO fire are both per the same RFC 8985&lt;br /&gt;
clause.  The clamp-and-skip path in the regular SACK-mark loop is&lt;br /&gt;
incidentally idempotent on any leftover case-1 or case-2 block&lt;br /&gt;
(&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; and the inner loop&lt;br /&gt;
skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;; case-2 re-NULLs slots already marked&lt;br /&gt;
received by later blocks), so block[0] is harmless even when fed&lt;br /&gt;
to the loop.&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity. Ouroboros flow allocation runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys. This is finer-grained than QUIC (per-connection, RFC 9001, where one handshake covers all multiplexed streams) and finer-grained than typical IPsec deployment (per-host-pair Security Associations, SAs). Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH + post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection. The AEAD layer itself does NOT carry an explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec. 3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then discarded either as a duplicate (still inside the receive window or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has advanced since the original packet was delivered. RAW (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore no replay protection at the AEAD layer either; deployments that need replay rejection on RAW flows SHOULD use SVC_MESSAGE.&lt;br /&gt;
&lt;br /&gt;
Layering. The AEAD wrap sits below FRCP on the data path, so RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity + confidentiality scope as FRCP-engaged flows - whatever the process and FRCP (if any) put on the wire is what the AEAD authenticates. No DTLS-equivalent layering is required for confidentiality and integrity; replay protection above AEAD is a separate concern as noted above.&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1921</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1921"/>
		<updated>2026-05-17T15:24:25Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 1.3. SACK payload */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
are in network byte order; &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place &amp;lt;code&amp;gt;pci-&amp;gt;hcs&amp;lt;/code&amp;gt; read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet; the trailer is written as a raw &amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; (the same convention as &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;: opaque on the wire as long as both peers run compatible builds).  The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it.  It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&lt;br /&gt;
Encoding.  When a duplicate is observed the receiver arms a&lt;br /&gt;
single-slot pending report (&amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;dsack_valid&amp;lt;/code&amp;gt;,&lt;br /&gt;
latest-wins across multiple arms before the next emit).  On the&lt;br /&gt;
next outbound SACK the receiver prepends &amp;lt;code&amp;gt;block[0] = [dsack_seqno,&lt;br /&gt;
dsack_seqno + 1)&amp;lt;/code&amp;gt; - always a one-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range - and clears the&lt;br /&gt;
flag.  The three arm sites are listed in [[#10. Cumulative + selective ACK|Section 10]]; case-1 sites&lt;br /&gt;
yield &amp;lt;code&amp;gt;dsack_seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt; (the next &amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;), and the&lt;br /&gt;
case-2 site (&amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict) yields &amp;lt;code&amp;gt;dsack_seqno&amp;lt;/code&amp;gt; in&lt;br /&gt;
&amp;lt;code&amp;gt;[rcv_cr.lwe, rcv_cr.rwe)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Detection.  The sender classifies &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; by its relation to&lt;br /&gt;
&amp;lt;code&amp;gt;pci.ackno&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, pci.ackno)&amp;lt;/code&amp;gt; AND &amp;lt;code&amp;gt;pci.ackno - blocks[0].start &amp;amp;lt;= MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  The lag bound rejects stale or spoofed reports beyond one receive window.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range (with at least one endpoint differing) of some &amp;lt;code&amp;gt;blocks[i&amp;amp;gt;0]&amp;lt;/code&amp;gt; - i.e. the same packet&#039;s remaining SACK blocks already describe the duplicated &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; as received.&lt;br /&gt;
&lt;br /&gt;
On detect, the sender:&lt;br /&gt;
&lt;br /&gt;
* bumps &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; by 1, capped at &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; (= 20), per RFC 8985 sec. 6.2 step 4;&lt;br /&gt;
* snapshots &amp;lt;code&amp;gt;dsack_lwe_snap = snd_cr.lwe&amp;lt;/code&amp;gt;, resetting the 16-cum-ACK halving counter so the multiplier doesn&#039;t decay while D-SACK evidence is still arriving;&lt;br /&gt;
* excludes &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; from the gap-marking loop (&amp;lt;code&amp;gt;n_real = n - 1&amp;lt;/code&amp;gt;), so a D-SACK alone never enters NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks count as gaps.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; halving cadence (once per 16 cumulatively-ACK&#039;d&lt;br /&gt;
seqnos since the most-recent D-SACK arrival or halve event) and&lt;br /&gt;
the reset-to-1 on a HoL RTO fire are both per the same RFC 8985&lt;br /&gt;
clause.  The clamp-and-skip path in the regular SACK-mark loop is&lt;br /&gt;
incidentally idempotent on any leftover case-1 or case-2 block&lt;br /&gt;
(&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; and the inner loop&lt;br /&gt;
skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;; case-2 re-NULLs slots already marked&lt;br /&gt;
received by later blocks), so block[0] is harmless even when fed&lt;br /&gt;
to the loop.&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity. Ouroboros flow allocation runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys. This is finer-grained than QUIC (per-connection, RFC 9001, where one handshake covers all multiplexed streams) and finer-grained than typical IPsec deployment (per-host-pair Security Associations, SAs). Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH + post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection. The AEAD layer itself does NOT carry an explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec. 3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then discarded either as a duplicate (still inside the receive window or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has advanced since the original packet was delivered. RAW (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore no replay protection at the AEAD layer either; deployments that need replay rejection on RAW flows SHOULD use SVC_MESSAGE.&lt;br /&gt;
&lt;br /&gt;
Layering. The AEAD wrap sits below FRCP on the data path, so RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity + confidentiality scope as FRCP-engaged flows - whatever the process and FRCP (if any) put on the wire is what the AEAD authenticates. No DTLS-equivalent layering is required for confidentiality and integrity; replay protection above AEAD is a separate concern as noted above.&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1920</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1920"/>
		<updated>2026-05-17T15:17:17Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 1.3. SACK payload */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
are in network byte order; &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place &amp;lt;code&amp;gt;pci-&amp;gt;hcs&amp;lt;/code&amp;gt; read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet; the trailer is written as a raw &amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; (the same convention as &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;: opaque on the wire as long as both peers run compatible builds).  The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it.  It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&amp;lt;code&amp;gt;Block[0]&amp;lt;/code&amp;gt; carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, ackno)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ackno - blocks[0].start&amp;lt;/code&amp;gt; is within &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  A single duplicate &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; observed below the cumulative ACK.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range of some &amp;lt;code&amp;gt;blocks[i&amp;gt;0]&amp;lt;/code&amp;gt; (not exactly equal).  Reports a duplicate of an in-window &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that the same packet&#039;s remaining SACK blocks already describe as received.&lt;br /&gt;
&lt;br /&gt;
On receipt the sender feeds &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; into the RACK&lt;br /&gt;
&amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks&lt;br /&gt;
count as gaps.  The normal SACK-mark loop processes &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;&lt;br /&gt;
idempotently regardless: the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt;, the&lt;br /&gt;
inner loop then skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;) and case-2 a re-NULL of&lt;br /&gt;
slots already marked received by later blocks.&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity. Ouroboros flow allocation runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys. This is finer-grained than QUIC (per-connection, RFC 9001, where one handshake covers all multiplexed streams) and finer-grained than typical IPsec deployment (per-host-pair Security Associations, SAs). Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH + post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection. The AEAD layer itself does NOT carry an explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec. 3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then discarded either as a duplicate (still inside the receive window or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has advanced since the original packet was delivered. RAW (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore no replay protection at the AEAD layer either; deployments that need replay rejection on RAW flows SHOULD use SVC_MESSAGE.&lt;br /&gt;
&lt;br /&gt;
Layering. The AEAD wrap sits below FRCP on the data path, so RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity + confidentiality scope as FRCP-engaged flows - whatever the process and FRCP (if any) put on the wire is what the AEAD authenticates. No DTLS-equivalent layering is required for confidentiality and integrity; replay protection above AEAD is a separate concern as noted above.&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1919</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1919"/>
		<updated>2026-05-17T15:12:21Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 16.5. Security considerations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
are in network byte order; &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place &amp;lt;code&amp;gt;pci-&amp;gt;hcs&amp;lt;/code&amp;gt; read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet; the trailer is written as a raw &amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; (the same convention as &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;: opaque on the wire as long as both peers run compatible builds).  The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it.  It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&amp;lt;code&amp;gt;Block[0]&amp;lt;/code&amp;gt; carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, ackno)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ackno - blocks[0].start&amp;lt;/code&amp;gt; is within &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  A single duplicate &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; observed below the cumulative ACK.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range of some &amp;lt;code&amp;gt;blocks[i&amp;gt;0]&amp;lt;/code&amp;gt; (not exactly equal).  Reports a duplicate of an in-window &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that the same packet&#039;s remaining SACK blocks already describe as received.&lt;br /&gt;
&lt;br /&gt;
Senders that do not implement D-SACK process &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; through the&lt;br /&gt;
normal SACK-mark loop and the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt;, the inner&lt;br /&gt;
loop then skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;) and case-2 idempotent (same slots&lt;br /&gt;
NULL&#039;d twice).  D-SACK-aware senders feed the report into the RACK&lt;br /&gt;
&amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks&lt;br /&gt;
count as gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity. Ouroboros flow allocation runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys. This is finer-grained than QUIC (per-connection, RFC 9001, where one handshake covers all multiplexed streams) and finer-grained than typical IPsec deployment (per-host-pair Security Associations, SAs). Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH + post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection. The AEAD layer itself does NOT carry an explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec. 3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then discarded either as a duplicate (still inside the receive window or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has advanced since the original packet was delivered. RAW (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore no replay protection at the AEAD layer either; deployments that need replay rejection on RAW flows SHOULD use SVC_MESSAGE.&lt;br /&gt;
&lt;br /&gt;
Layering. The AEAD wrap sits below FRCP on the data path, so RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity + confidentiality scope as FRCP-engaged flows - whatever the process and FRCP (if any) put on the wire is what the AEAD authenticates. No DTLS-equivalent layering is required for confidentiality and integrity; replay protection above AEAD is a separate concern as noted above.&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1918</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1918"/>
		<updated>2026-05-17T15:11:27Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 16.5. Security considerations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
are in network byte order; &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place &amp;lt;code&amp;gt;pci-&amp;gt;hcs&amp;lt;/code&amp;gt; read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet; the trailer is written as a raw &amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; (the same convention as &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;: opaque on the wire as long as both peers run compatible builds).  The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it.  It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&amp;lt;code&amp;gt;Block[0]&amp;lt;/code&amp;gt; carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, ackno)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ackno - blocks[0].start&amp;lt;/code&amp;gt; is within &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  A single duplicate &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; observed below the cumulative ACK.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range of some &amp;lt;code&amp;gt;blocks[i&amp;gt;0]&amp;lt;/code&amp;gt; (not exactly equal).  Reports a duplicate of an in-window &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that the same packet&#039;s remaining SACK blocks already describe as received.&lt;br /&gt;
&lt;br /&gt;
Senders that do not implement D-SACK process &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; through the&lt;br /&gt;
normal SACK-mark loop and the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt;, the inner&lt;br /&gt;
loop then skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;) and case-2 idempotent (same slots&lt;br /&gt;
NULL&#039;d twice).  D-SACK-aware senders feed the report into the RACK&lt;br /&gt;
&amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks&lt;br /&gt;
count as gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity. Ouroboros flow allocation runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys. This is finer-grained than QUIC (per-connection, RFC 9001, where one handshake covers all multiplexed streams) and finer-grained than typical IPsec deployment (per-host-pair Security Associations, SAs). Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH + post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection. The AEAD layer itself does NOT carry an explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec. 3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then discarded either as a duplicate (still inside the receive window or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has advanced since the original packet was delivered. RAW (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore no replay protection at the AEAD layer either; deployments that need replay rejection on RAW flows SHOULD use SVC_MESSAGE.&lt;br /&gt;
&lt;br /&gt;
Layering. The AEAD wrap sits below FRCP on the data path, so RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity + confidentiality scope as FRCP-engaged flows - whatever the IPCP and FRCP (if any) put on the wire is what the AEAD authenticates. No DTLS-equivalent layering is required for confidentiality and integrity; replay protection above AEAD is a separate concern as noted above.&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1917</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1917"/>
		<updated>2026-05-17T14:59:41Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 15. Heritage and adopted techniques */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
are in network byte order; &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place &amp;lt;code&amp;gt;pci-&amp;gt;hcs&amp;lt;/code&amp;gt; read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet; the trailer is written as a raw &amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; (the same convention as &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;: opaque on the wire as long as both peers run compatible builds).  The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it.  It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&amp;lt;code&amp;gt;Block[0]&amp;lt;/code&amp;gt; carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, ackno)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ackno - blocks[0].start&amp;lt;/code&amp;gt; is within &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  A single duplicate &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; observed below the cumulative ACK.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range of some &amp;lt;code&amp;gt;blocks[i&amp;gt;0]&amp;lt;/code&amp;gt; (not exactly equal).  Reports a duplicate of an in-window &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that the same packet&#039;s remaining SACK blocks already describe as received.&lt;br /&gt;
&lt;br /&gt;
Senders that do not implement D-SACK process &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; through the&lt;br /&gt;
normal SACK-mark loop and the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt;, the inner&lt;br /&gt;
loop then skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;) and case-2 idempotent (same slots&lt;br /&gt;
NULL&#039;d twice).  D-SACK-aware senders feed the report into the RACK&lt;br /&gt;
&amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks&lt;br /&gt;
count as gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 250 us is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity.  FRCP runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so&lt;br /&gt;
each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys.  This is&lt;br /&gt;
finer-grained than QUIC (per-connection, RFC 9001, where one&lt;br /&gt;
handshake covers all multiplexed streams) and finer-grained than&lt;br /&gt;
typical IPsec deployment (per-host-pair Security Associations,&lt;br /&gt;
SAs).  Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral&lt;br /&gt;
Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH +&lt;br /&gt;
post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection.  The AEAD layer itself does NOT carry an&lt;br /&gt;
explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec.&lt;br /&gt;
3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates&lt;br /&gt;
the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then&lt;br /&gt;
discarded either as a duplicate (still inside the receive window)&lt;br /&gt;
or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has&lt;br /&gt;
advanced since the original packet was delivered.  RAW&lt;br /&gt;
(&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore&lt;br /&gt;
no replay protection at the AEAD layer either; deployments that&lt;br /&gt;
need replay rejection on RAW flows MUST provide it at a higher&lt;br /&gt;
layer.&lt;br /&gt;
&lt;br /&gt;
Layering.  The AEAD wrap sits below FRCP on the data path, so&lt;br /&gt;
RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent&lt;br /&gt;
service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity +&lt;br /&gt;
confidentiality scope as FRCP-engaged flows - whatever the IPCP&lt;br /&gt;
and FRCP (if any) put on the wire is what the AEAD authenticates.&lt;br /&gt;
No DTLS-equivalent layering is required for confidentiality and&lt;br /&gt;
integrity; replay protection above AEAD is a separate concern as&lt;br /&gt;
noted above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1916</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1916"/>
		<updated>2026-05-17T14:47:17Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 9. Pre-DRF NACK */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
are in network byte order; &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place &amp;lt;code&amp;gt;pci-&amp;gt;hcs&amp;lt;/code&amp;gt; read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet; the trailer is written as a raw &amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; (the same convention as &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;: opaque on the wire as long as both peers run compatible builds).  The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it.  It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&amp;lt;code&amp;gt;Block[0]&amp;lt;/code&amp;gt; carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, ackno)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ackno - blocks[0].start&amp;lt;/code&amp;gt; is within &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  A single duplicate &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; observed below the cumulative ACK.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range of some &amp;lt;code&amp;gt;blocks[i&amp;gt;0]&amp;lt;/code&amp;gt; (not exactly equal).  Reports a duplicate of an in-window &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that the same packet&#039;s remaining SACK blocks already describe as received.&lt;br /&gt;
&lt;br /&gt;
Senders that do not implement D-SACK process &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; through the&lt;br /&gt;
normal SACK-mark loop and the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt;, the inner&lt;br /&gt;
loop then skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;) and case-2 idempotent (same slots&lt;br /&gt;
NULL&#039;d twice).  D-SACK-aware senders feed the report into the RACK&lt;br /&gt;
&amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks&lt;br /&gt;
count as gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds (&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the receiver-driven nudge that asks the sender to re-transmit the head of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK has exactly one role: lost first-of-run (DRF) packet recovery. Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver. The NACK fires the moment a stale receiver sees DATA without DRF, telling the sender to re-emit the head-of-line (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).  Mid-stream loss is NOT NACK-driven; it is recovered by the sender&#039;s RTO, fast retransmit, and SACK-driven retransmit paths ([[#8. Retransmission|Section 8]]) only.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed on a NACK re-emit, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 5 ms is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity.  FRCP runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so&lt;br /&gt;
each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys.  This is&lt;br /&gt;
finer-grained than QUIC (per-connection, RFC 9001, where one&lt;br /&gt;
handshake covers all multiplexed streams) and finer-grained than&lt;br /&gt;
typical IPsec deployment (per-host-pair Security Associations,&lt;br /&gt;
SAs).  Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral&lt;br /&gt;
Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH +&lt;br /&gt;
post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection.  The AEAD layer itself does NOT carry an&lt;br /&gt;
explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec.&lt;br /&gt;
3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates&lt;br /&gt;
the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then&lt;br /&gt;
discarded either as a duplicate (still inside the receive window)&lt;br /&gt;
or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has&lt;br /&gt;
advanced since the original packet was delivered.  RAW&lt;br /&gt;
(&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore&lt;br /&gt;
no replay protection at the AEAD layer either; deployments that&lt;br /&gt;
need replay rejection on RAW flows MUST provide it at a higher&lt;br /&gt;
layer.&lt;br /&gt;
&lt;br /&gt;
Layering.  The AEAD wrap sits below FRCP on the data path, so&lt;br /&gt;
RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent&lt;br /&gt;
service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity +&lt;br /&gt;
confidentiality scope as FRCP-engaged flows - whatever the IPCP&lt;br /&gt;
and FRCP (if any) put on the wire is what the AEAD authenticates.&lt;br /&gt;
No DTLS-equivalent layering is required for confidentiality and&lt;br /&gt;
integrity; replay protection above AEAD is a separate concern as&lt;br /&gt;
noted above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1915</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1915"/>
		<updated>2026-05-17T14:40:10Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:FRCP - Flow and Retransmission Control Protocol}}&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in &amp;lt;code&amp;gt;src/lib/frct.c&amp;lt;/code&amp;gt;.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the &amp;lt;code&amp;gt;FRCT_&amp;lt;/code&amp;gt; prefix&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in &amp;lt;code&amp;gt;BCP&amp;lt;/code&amp;gt; 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
;&amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:Nanoseconds.&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;before(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;(int32_t)(a - b) &amp;amp;lt; 0&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;after(a, b)&amp;lt;/code&amp;gt;&lt;br /&gt;
:&amp;lt;code&amp;gt;before(b, a)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
;&amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
;&amp;lt;code&amp;gt;EWMA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Exponentially Weighted Moving Average.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTO&amp;lt;/code&amp;gt;&lt;br /&gt;
:Retransmission Timeout, &amp;lt;code&amp;gt;max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer, ACK delay) and &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer,&lt;br /&gt;
retransmission window) are defined in [[#8. Retransmission|Section 8]]; &amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in [[#2.1. Per-flow state|Section 2.1]] (the &amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; field)&lt;br /&gt;
with heritage in [[#15. Heritage and adopted techniques|Section 15]].&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
are in network byte order; &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place &amp;lt;code&amp;gt;pci-&amp;gt;hcs&amp;lt;/code&amp;gt; read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
[[#1.5. Stream PCI extension|Section 1.5]]); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt;&lt;br /&gt;
:feature/type bitmap (see [[#1.2. Flag bits|Section 1.2]]).&lt;br /&gt;
;&amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;&lt;br /&gt;
:CRC-16-CCITT-FALSE Header Check Sequence (HCS) over &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; (+ stream extension when present); the two octets of the &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt; field itself are omitted from the CRC input.  Verified on receive before any flag-driven dispatch.&lt;br /&gt;
;&amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt;&lt;br /&gt;
:receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-flow sequence number.&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;&lt;br /&gt;
:cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]]).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Layer !! Scope&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| The FRCP packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ PCI + body + CRC-32 ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| CRC-32 covers the body only (PCI is in HCS); appended iff &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; on DATA, or on every SACK packet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[ AEAD-wrap of above ]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Iff Authenticated Encryption with Associated Data (AEAD) is enabled.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* HCS in the PCI covers the header fields on every packet and is verified before any flag-driven dispatch.&lt;br /&gt;
* The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial &amp;lt;code&amp;gt;0xEDB88320&amp;lt;/code&amp;gt;, init &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;, xor-out &amp;lt;code&amp;gt;0xFFFFFFFF&amp;lt;/code&amp;gt;) covers the body on DATA when &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; and on every SACK packet; the trailer is written as a raw &amp;lt;code&amp;gt;uint32_t&amp;lt;/code&amp;gt; (the same convention as &amp;lt;code&amp;gt;hcs&amp;lt;/code&amp;gt;: opaque on the wire as long as both peers run compatible builds).  The PCI is not under the CRC (Cyclic Redundancy Check) because the HCS already protects it.  It is appended before AEAD encryption and therefore rides inside the AEAD wrap when both are active; the AEAD tag (~2^-128 forgery probability) dominates the CRC (~2^-32) for integrity in that mode but the CRC trailer is currently retained.&lt;br /&gt;
* When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP packet is wrapped with AEAD inside the shared-memory packet buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt;); the packet grows by the AEAD overhead, namely a leading nonce / Initialization Vector (IV) of &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_ivsz&amp;lt;/code&amp;gt;) and a trailing authentication tag of &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; bytes (&amp;lt;code&amp;gt;crypt_get_tagsz&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per [[#1.1. PCI header|Section 1.1]]; bit 0 is the MSB of the&lt;br /&gt;
16-bit &amp;lt;code&amp;gt;flags&amp;lt;/code&amp;gt; field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Bit !! Mask !! Name !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || &amp;lt;code&amp;gt;0x8000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt; || Carries caller payload&lt;br /&gt;
|-&lt;br /&gt;
| 1 || &amp;lt;code&amp;gt;0x4000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;DRF&amp;lt;/code&amp;gt; || Data Run Flag: start of a fresh run&lt;br /&gt;
|-&lt;br /&gt;
| 2 || &amp;lt;code&amp;gt;0x2000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt; || Acknowledgement: &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field valid&lt;br /&gt;
|-&lt;br /&gt;
| 3 || &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt; || Negative ACK; &amp;lt;code&amp;gt;seqno = arrival_seqno-1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4 || &amp;lt;code&amp;gt;0x0800&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt; || Flow Control: &amp;lt;code&amp;gt;window&amp;lt;/code&amp;gt; field valid (&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || &amp;lt;code&amp;gt;0x0400&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt; || Rendezvous probe (window-closed)&lt;br /&gt;
|-&lt;br /&gt;
| 6 || &amp;lt;code&amp;gt;0x0200&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; || First Fragment (role bit 0; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 7 || &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; || Last Fragment (role bit 1; see below)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RXM&amp;lt;/code&amp;gt; || Retransmission&lt;br /&gt;
|-&lt;br /&gt;
| 9 || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt; || Selective ACK block list in payload&lt;br /&gt;
|-&lt;br /&gt;
| 10 || &amp;lt;code&amp;gt;0x0020&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt; || RTT Probe / echo (payload follows)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || &amp;lt;code&amp;gt;0x0010&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt; || Keepalive&lt;br /&gt;
|-&lt;br /&gt;
| 12 || &amp;lt;code&amp;gt;0x0008&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt; || End-of-stream marker (stream mode)&lt;br /&gt;
|-&lt;br /&gt;
| 13-15 || -- || -- || Reserved (MUST be zero)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FFGM !! LFGM !! Role&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 1 || Sole / un-fragmented SDU (begin AND end)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0 || First fragment of a multi-fragment SDU&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Middle fragment&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || Last fragment&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see [[#2.2. Service modes (orthogonal axes)|Section 2.2]])&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;, see [[#16. Stream-mode flows|Section 16]]) there are&lt;br /&gt;
no SDU boundaries to encode, so &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (&amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(&amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;FLOWFRDONLY&amp;lt;/code&amp;gt;), during linger drain, and at &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt; at the FIN&#039;s&lt;br /&gt;
start offset; &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns 0 (end-of-file, &amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) once buffered&lt;br /&gt;
bytes have been drained up to &amp;lt;code&amp;gt;byte_fin&amp;lt;/code&amp;gt;.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension ([[#1.5. Stream PCI extension|Section 1.5]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the &amp;lt;code&amp;gt;FRCT_ACK | FRCT_FC | FRCT_SACK&amp;lt;/code&amp;gt; flag bits set&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then &amp;lt;code&amp;gt;n_blocks&amp;lt;/code&amp;gt; pairs of&lt;br /&gt;
32-bit start/end seqnos describing &#039;&#039;present&#039;&#039; (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;n_blocks &amp;amp;lt;= SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by &amp;lt;code&amp;gt;(frag_mtu - PCI - 4) / 8&amp;lt;/code&amp;gt; blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; field (&amp;lt;code&amp;gt;after(start[i], ackno)&amp;lt;/code&amp;gt;).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
&amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators defined in the Notation block.&lt;br /&gt;
&amp;lt;code&amp;gt;Block[0]&amp;lt;/code&amp;gt; carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
;case 1 (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;before(blocks[0].start, ackno)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ackno - blocks[0].start&amp;lt;/code&amp;gt; is within &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;== RQ_SIZE&amp;lt;/code&amp;gt;).  A single duplicate &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; observed below the cumulative ACK.&lt;br /&gt;
;case 2 (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
:&amp;lt;code&amp;gt;blocks[0]&amp;lt;/code&amp;gt; is a sub-range of some &amp;lt;code&amp;gt;blocks[i&amp;gt;0]&amp;lt;/code&amp;gt; (not exactly equal).  Reports a duplicate of an in-window &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that the same packet&#039;s remaining SACK blocks already describe as received.&lt;br /&gt;
&lt;br /&gt;
Senders that do not implement D-SACK process &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; through the&lt;br /&gt;
normal SACK-mark loop and the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (&amp;lt;code&amp;gt;start &amp;amp;lt; snd_cr.lwe&amp;lt;/code&amp;gt; clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt;, the inner&lt;br /&gt;
loop then skips &amp;lt;code&amp;gt;k == snd_cr.lwe&amp;lt;/code&amp;gt;) and case-2 idempotent (same slots&lt;br /&gt;
NULL&#039;d twice).  D-SACK-aware senders feed the report into the RACK&lt;br /&gt;
&amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see [[#8. Retransmission|Section 8]]); only non-D-SACK blocks&lt;br /&gt;
count as gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the &amp;lt;code&amp;gt;FRCT_RTTP&amp;lt;/code&amp;gt; flag&lt;br /&gt;
set (bit numbering per [[#1.1. PCI header|Section 1.1]]).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
;&amp;lt;code&amp;gt;echo_id&amp;lt;/code&amp;gt;&lt;br /&gt;
:peer&#039;s &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt;, 0 on outbound probe.&lt;br /&gt;
;&amp;lt;code&amp;gt;nonce&amp;lt;/code&amp;gt;&lt;br /&gt;
:random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (&amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt;) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per [[#1.1. PCI header|Section 1.1]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset of the first payload byte in the stream.&lt;br /&gt;
;&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;&lt;br /&gt;
:octet offset one past the last payload byte; &amp;lt;code&amp;gt;end - start&amp;lt;/code&amp;gt; equals the on-wire payload length.&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; not equal to the prior packet&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; the&lt;br /&gt;
slot is silently dropped at delivery time ([[#16. Stream-mode flows|Section 16]]) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (this PCI&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; field) and a&lt;br /&gt;
separate stream byte position (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;,&lt;br /&gt;
per-slot &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; flags, and a sample-fence &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; (see [[#2.1. Per-flow state|Section 2.1]]&lt;br /&gt;
and [[#12. RTT estimation|Section 12]]).  FRCP&#039;s fixed-32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;&lt;br /&gt;
/ &amp;lt;code&amp;gt;after()&amp;lt;/code&amp;gt; comparators ([[#1.3. SACK payload|Section 1.3]]) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in &amp;lt;code&amp;gt;before()&amp;lt;/code&amp;gt;).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; at 128 MiB (&amp;lt;code&amp;gt;FRCT_STREAM_RING_SZ_MAX&amp;lt;/code&amp;gt;),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform &amp;lt;code&amp;gt;size_t&amp;lt;/code&amp;gt; and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: oldest unacked &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (cumulative ACK boundary as seen by sender); rcv: next in-order &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; expected&lt;br /&gt;
;&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: peer-advertised right window edge; rcv: locally-advertised right window edge&lt;br /&gt;
;&amp;lt;code&amp;gt;cflags&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u8&amp;lt;/code&amp;gt;&lt;br /&gt;
:per-direction feature flags: retransmission (&amp;lt;code&amp;gt;FRCTFRTX&amp;lt;/code&amp;gt;), receiver flow control (&amp;lt;code&amp;gt;FRCTFRESCNTL&amp;lt;/code&amp;gt;), linger-on-close (&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt;); see &amp;lt;code&amp;gt;&amp;amp;lt;ouroboros/fccntl.h&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
;&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: next &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; to send; rcv: force-ACK trigger - set on a stale or dup DATA so the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; emits a fresh cumulative ACK&lt;br /&gt;
;&amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;u32&amp;lt;/code&amp;gt;&lt;br /&gt;
:snd: &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; counter for standalone ACK-bearing control packets (delayed ACK, SACK, final ACK on dealloc); not bumped on piggybacked ACK riding a DATA packet (which uses the DATA &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;).  Used by wire-dup ACK detection; rcv: incoming-ACK dedup tracker&lt;br /&gt;
;&amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:last activity (used by inactivity / DRF)&lt;br /&gt;
;&amp;lt;code&amp;gt;inact&amp;lt;/code&amp;gt; : &amp;lt;code&amp;gt;ns&amp;lt;/code&amp;gt;&lt;br /&gt;
:inactivity threshold; sender = &amp;lt;code&amp;gt;3*mpl + a + r + 1s&amp;lt;/code&amp;gt;, receiver = &amp;lt;code&amp;gt;2*mpl + a + r + 1s&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;mpl&amp;lt;/code&amp;gt; is the Maximum Packet Lifetime (delta-t terminology; see [[#15. Heritage and adopted techniques|Section 15]]); &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;r&amp;lt;/code&amp;gt; are the FRCT a-timer and r-timer bounds (see [[#8. Retransmission|Section 8]]).  The asymmetry is load-bearing for pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring &amp;lt;code&amp;gt;snd_slots[RQ_SIZE]&amp;lt;/code&amp;gt; keyed by&lt;br /&gt;
&amp;lt;code&amp;gt;(seqno mod RQ_SIZE)&amp;lt;/code&amp;gt;.  Each slot tracks its retransmit entry (&amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring &amp;lt;code&amp;gt;rcv_slots[RQ_SIZE]&amp;lt;/code&amp;gt;&lt;br /&gt;
(referred to as &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant &amp;lt;code&amp;gt;rwe - lwe &amp;amp;lt;= RQ_SIZE&amp;lt;/code&amp;gt; holds: on each consume&lt;br /&gt;
the receiver advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; by the consumed count, capping the&lt;br /&gt;
receive window at &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt; is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; ([[#4. Sequence-number rotation (DRF)|Section 4]]) to mark the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive; the &amp;lt;code&amp;gt;qosspec_t&amp;lt;/code&amp;gt; passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (&amp;lt;code&amp;gt;SOCK_STREAM&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;SOCK_DGRAM&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = unordered (no FRCP engagement: raw datagrams, no PCI on the wire, UDP-equivalent at this layer); 1 = message-ordered (FRCP engaged; SDU boundaries preserved across fragmentation); 2 = stream (byte-oriented, no SDU boundaries; FRTX required)&lt;br /&gt;
;&amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt;&lt;br /&gt;
:0 = lossless service requested: FRTX retransmit machinery engages ([[#8. Retransmission|Section 8]]); MUST be 0 for &amp;lt;code&amp;gt;service=2&amp;lt;/code&amp;gt;.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
;&amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bit Error Rate tolerance.  0 = error-free service requested: a CRC trailer is appended after the body of DATA packets and verified on receive (added / checked outside the FRCP PCI; see [[#1.1. PCI header|Section 1.1]]).  Non-zero = peer accepts errors; trailer omitted.  SACK control packets carry a CRC32 trailer regardless of &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; gate applies to DATA only.&lt;br /&gt;
;&amp;lt;code&amp;gt;timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
:Peer-timeout (ms); 0 disables the keepalive timer.  Independent of FRCP engagement.&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; by &amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt;&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by &amp;lt;code&amp;gt;include/ouroboros/qos.h&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Cube !! &amp;lt;code&amp;gt;service&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;loss&amp;lt;/code&amp;gt; !! &amp;lt;code&amp;gt;ber&amp;lt;/code&amp;gt; !! Engaged&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw&amp;lt;/code&amp;gt; || 0 || 1 || 1 || Raw passthrough&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_raw_safe&amp;lt;/code&amp;gt; || 0 || 1 || 0 || Raw + CRC trailer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; || 1 || 1 || 1 || FRCP, no FRTX, no CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_rt_safe&amp;lt;/code&amp;gt; || 1 || 1 || 0 || FRCP, no FRTX, CRC&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_msg&amp;lt;/code&amp;gt; || 1 || 0 || 0 || FRCP + FRTX&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;qos_stream&amp;lt;/code&amp;gt; || 2 || 0 || 0 || FRCP + FRTX, stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service == SVC_STREAM&amp;lt;/code&amp;gt; (2) requires &amp;lt;code&amp;gt;loss == 0&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;flow_accept&amp;lt;/code&amp;gt; reject the pair otherwise with &amp;lt;code&amp;gt;-EINVAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
* FRTX requires FRCP engagement (&amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;); requesting &amp;lt;code&amp;gt;loss = 0&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;service = SVC_RAW&amp;lt;/code&amp;gt; is structurally a no-op because no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; is created.&lt;br /&gt;
* The &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; build flag globally forces &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;.  Note: this flag defaults to ON, so default builds ship with CRC disabled until &amp;lt;code&amp;gt;QOS_DISABLE_CRC&amp;lt;/code&amp;gt; is set to OFF.&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force &amp;lt;code&amp;gt;ber = 0&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;service != SVC_RAW&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;code&amp;gt;qos_rt&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;ber = 1&amp;lt;/code&amp;gt;, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS ([[#1.1. PCI header|Section 1.1]])&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (&amp;lt;code&amp;gt;service = SVC_MESSAGE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loss &amp;amp;gt; 0&amp;lt;/code&amp;gt;) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Value !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Slot ring / rcv window width&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;START_WINDOW&amp;lt;/code&amp;gt; || compile-time, power of 2 (default 128) || Initial &amp;lt;code&amp;gt;rwe-lwe&amp;lt;/code&amp;gt; after rotate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MAX(250 us build-tunable, 1&amp;amp;lt;&amp;amp;lt;RXMQ_RES)&amp;lt;/code&amp;gt;; per-flow via &amp;lt;code&amp;gt;fccntl&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;FRCTSRTOMIN&amp;lt;/code&amp;gt;).  Default ~1 ms with &amp;lt;code&amp;gt;RXMQ_RES=20&amp;lt;/code&amp;gt;. || RTO floor; also floored at the retransmit-wheel resolution (~1 ms by default).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt; || 20 || Backoff shift cap&lt;br /&gt;
|-&lt;br /&gt;
| RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;MIN(reo_wnd_mult * min_RTT/4, SRTT)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; scales on D-SACK, cap 20 || Reorder window; per RFC 8985 sec. 6.2; &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per sec. 6.2 step 4&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; || 300 s (5 min, Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; windowed re-anchor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_WND_MULT_MAX&amp;lt;/code&amp;gt; || 20 (RFC 8985 sec. 6.2 step 4) || &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;REO_DECAY_PKTS&amp;lt;/code&amp;gt; || 16 (RFC 8985 sec. 6.2 step 4 / &amp;lt;code&amp;gt;RACK.reo_wnd_persist&amp;lt;/code&amp;gt;) || Fresh-ACK&#039;d seq count per halving&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_DSACK_LAG&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt; || D-SACK sanity cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTT_QUARANTINE&amp;lt;/code&amp;gt; || 32 (&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; steps) || NewReno gate pad&lt;br /&gt;
|-&lt;br /&gt;
| SACK rate-limit || &amp;lt;code&amp;gt;SACK_MIN_GAP_NS&amp;lt;/code&amp;gt; (250 us, fixed) || Min SACK gap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_MAX_BLOCKS&amp;lt;/code&amp;gt; || 2048 (wire cap; per-flow capped at &amp;lt;code&amp;gt;(frag_mtu-PCI-4)/8&amp;lt;/code&amp;gt;) || Per-SACK block cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; || 32 || Per-pass staged retransmit cap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; || 3 (RFC 8985 default) || Hybrid fast-rxm trigger ([[#8. Retransmission|Section 8]])&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MDEV_MUL&amp;lt;/code&amp;gt; || 2 (build-tunable via &amp;lt;code&amp;gt;FRCT_RTO_MDEV_MULTIPLIER&amp;lt;/code&amp;gt;) || &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; shift in &amp;lt;code&amp;gt;RTO = srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| RTTP nonce || 16 octets || Echoed verbatim&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; || 8 || In-flight probes&lt;br /&gt;
|-&lt;br /&gt;
| RTT clamp || &amp;lt;code&amp;gt;16 * srtt&amp;lt;/code&amp;gt; || Probe-sample upper bound (ACK-derived RTT samples gated by Karn / recovery only)&lt;br /&gt;
|-&lt;br /&gt;
| Cold-probe cadence || 100 ms (rx-driven; see [[#12. RTT estimation|Section 12]]) || Pre-&amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; RTTP rate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt; || 100 ms || RDVS emit cadence&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; || 1 s || RDVS give-up&lt;br /&gt;
|-&lt;br /&gt;
| Delayed-ACK fire || &amp;lt;code&amp;gt;2 * TICTIME&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt; = FRCT tick granularity, default 5 ms; &amp;lt;code&amp;gt;2*TICTIME = 10 ms&amp;lt;/code&amp;gt; by default) || Fired after the first in-order DATA arrival; tick is build-tunable&lt;br /&gt;
|-&lt;br /&gt;
| NACK send cooldown || &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; when an &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; sample exists, else 100 ms || Pre-DRF NACK rate-limit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MAX_SDU&amp;lt;/code&amp;gt; || 1 MiB || Max reassembled SDU; configurable per flow&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
&amp;lt;code&amp;gt;headsz&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;tailsz&amp;lt;/code&amp;gt; and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.inact&amp;lt;/code&amp;gt; AND the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;),&lt;br /&gt;
&amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; rolls a random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per [[#3. Protocol parameters|Section 3]]); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
# If the SDU exceeds &amp;lt;code&amp;gt;(frag_mtu - data_hdr_len)&amp;lt;/code&amp;gt;, the caller (&amp;lt;code&amp;gt;dev.c&amp;lt;/code&amp;gt;) fans it out into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - data_hdr_len))&amp;lt;/code&amp;gt; fragments, each emitted via &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; as its own DATA packet with a per-fragment role ([[#7.2. Fragmentation and reassembly|Section 7.2]]); both FRTX and best-effort flows fragment.  Raw flows (no FRCP engagement, &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) carry no PCI and return &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; for any SDU larger than one packet at the layer below.  An SDU that fits in a single packet is sent as SOLE.  &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt; reserves PCI head room; sets DATA, plus DRF when the pipe is empty (&amp;lt;code&amp;gt;snd_cr.seqno == snd_cr.lwe&amp;lt;/code&amp;gt;).&lt;br /&gt;
# &amp;lt;code&amp;gt;seqno_rotate()&amp;lt;/code&amp;gt; if past sender inactivity and the pipe is empty ([[#4. Sequence-number rotation (DRF)|Section 4]]).&lt;br /&gt;
# Advertise FC (&amp;lt;code&amp;gt;pci.window = frcti_advert_rwe(frcti)&amp;lt;/code&amp;gt;, i.e. &amp;lt;code&amp;gt;rcv_cr.rwe&amp;lt;/code&amp;gt; clamped to &amp;lt;code&amp;gt;rcv_cr.lwe + ring_seq_cap&amp;lt;/code&amp;gt; in stream mode) when the receiver side is recent: &amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt; rcv_cr.inact&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Reliable mode (FRTX): leave &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; where it is; reset the slot at &amp;lt;code&amp;gt;RQ_SLOT(seqno)&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;snd_slots[p].time = now&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_slots[p].flags = 0&amp;lt;/code&amp;gt;); queue an &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; (saves a packet copy, arms a wheel timer at &amp;lt;code&amp;gt;now + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;).  Piggyback ACK (&amp;lt;code&amp;gt;pci.ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) while the a-timer for the most recent received DATA packet has not yet expired (&amp;lt;code&amp;gt;now - rcv_cr.act &amp;amp;lt;= t_a&amp;lt;/code&amp;gt;); on piggyback, set &amp;lt;code&amp;gt;rcv_cr.seqno = rcv_cr.lwe&amp;lt;/code&amp;gt; so the next delayed-ACK fire is suppressed.  See [[#8. Retransmission|Section 8]] for &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; semantics.&lt;br /&gt;
# Best-effort mode (no FRTX): advance &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; immediately (&amp;lt;code&amp;gt;snd_cr.lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;snd_cr.rwe = snd_cr.lwe + RQ_SIZE&amp;lt;/code&amp;gt;); no retransmit state.  No send-side RTT probe is armed in this mode (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt; requires an in-flight &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, which best-effort never has); the rx-driven cold seeder in &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; is the only probe path.&lt;br /&gt;
# In reliable mode, optionally arm an RTT probe ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;KA&amp;lt;/code&amp;gt;&lt;br /&gt;
:refresh &amp;lt;code&amp;gt;t_ka_rcv&amp;lt;/code&amp;gt;, honour piggybacked ACK.&lt;br /&gt;
;&amp;lt;code&amp;gt;RTTP&amp;lt;/code&amp;gt;&lt;br /&gt;
:probe (echo back nonce) or echo (verify nonce, sample RTT).&lt;br /&gt;
;&amp;lt;code&amp;gt;NACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:pre-DRF, sender-side handler.  See [[#9. Pre-DRF NACK|Section 9]].&lt;br /&gt;
;&amp;lt;code&amp;gt;RDVS&amp;lt;/code&amp;gt;&lt;br /&gt;
:reply with a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;); &amp;lt;code&amp;gt;rdlock&amp;lt;/code&amp;gt; only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow &amp;lt;code&amp;gt;frcti.lock&amp;lt;/code&amp;gt; held for writing&lt;br /&gt;
(&amp;lt;code&amp;gt;pthread_rwlock_wrlock&amp;lt;/code&amp;gt;) unless noted.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;&lt;br /&gt;
:Only meaningful when the receive side is stale.  On DRF (Data Run Flag): release &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; slots, rebase &amp;lt;code&amp;gt;rcv_cr&amp;lt;/code&amp;gt;, continue.  On stale DATA without DRF: fire a pre-DRF NACK if cooldown allows ([[#9. Pre-DRF NACK|Section 9]]), then discard the packet; on cooldown, drop without sending a NACK (a pending cumulative ACK from &amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; may still go out).  Non-DATA, non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; pure-DRF stale arrivals fall through after the DRF rebase branch.&lt;br /&gt;
&lt;br /&gt;
;DATA-only act refresh&lt;br /&gt;
:Refresh &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; only when &amp;lt;code&amp;gt;FRCT_DATA&amp;lt;/code&amp;gt; is set, so that non-DATA packets never block the next DRF rebase.&lt;br /&gt;
&lt;br /&gt;
;Wire-dup gate&lt;br /&gt;
:Before flag-driven dispatch, drop wire-duplicate ACKs and wire-duplicate DATA (&amp;lt;code&amp;gt;is_dup_ack&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt;).  The DATA check is bypassed for &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;-bearing arrivals so the piggybacked ACK / SACK / FC carried on a retransmitted DATA at an already-ACK&#039;d &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is still applied; the stale-in-window branch below then drops the packet.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;ACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Drop ACKs whose &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt; falls outside &amp;lt;code&amp;gt;(snd_cr.lwe, snd_cr.seqno]&amp;lt;/code&amp;gt;.  If &amp;lt;code&amp;gt;ackno == snd_cr.lwe&amp;lt;/code&amp;gt; (non-advancing cumulative ACK), drive RACK fast-retransmit consideration ([[#8. Retransmission|Section 8]]).  Otherwise advance &amp;lt;code&amp;gt;snd_cr.lwe = ackno&amp;lt;/code&amp;gt;, collapse &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; to 0 (Karn-gated by &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; on the just-acknowledged slot, the old head-of-line), reset &amp;lt;code&amp;gt;dup_thresh&amp;lt;/code&amp;gt; to 0, update &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the send-time of the slot at &amp;lt;code&amp;gt;ackno-1&amp;lt;/code&amp;gt; (consumed by RACK and SACK below), decay &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; per RFC 8985 sec. 6.2 step 4, exit NewReno-careful recovery (see [[#8. Retransmission|Section 8]]) on &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt;, and feed an RTT sample if eligible ([[#12. RTT estimation|Section 12]]).&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;SACK&amp;lt;/code&amp;gt;&lt;br /&gt;
:Walk the block list.  For each block (a present range above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;) NULL out &amp;lt;code&amp;gt;snd_slots[k].rxm&amp;lt;/code&amp;gt;, clear the slot&#039;s per-send flags, and advance &amp;lt;code&amp;gt;t_latest_ack&amp;lt;/code&amp;gt; to the latest send-time covered (the Forward Acknowledgement / fack equivalent, Mathis &amp;amp;amp; Mahdavi 1996); the first block whose start clamps to &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; skips this fack update so that a head-of-line clamp does not falsely advance fack.  For un-SACKed gaps below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt;, stage a retransmit per slot that is (1) still owned (&amp;lt;code&amp;gt;rxm != NULL&amp;lt;/code&amp;gt;), (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (the RFC 8985 sec. 6.2 hybrid trigger).  Mark the slot &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; and NULL the &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; at stage time.  Capped at &amp;lt;code&amp;gt;SACK_RXM_MAX&amp;lt;/code&amp;gt; staged retransmits per receive pass; what&#039;s left rides the next SACK.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;FC&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bump &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; (clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt;, never shrinks) and mark window open.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;DATA&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bounds-check &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; against window.  On stale-dup (&amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;), set &amp;lt;code&amp;gt;rcv_cr.seqno = seqno&amp;lt;/code&amp;gt; to force a fresh ACK on the next &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt;, then drop.  On accept: both FRTX and best-effort stash the packet-buffer index into &amp;lt;code&amp;gt;rq[seqno mod RQ_SIZE]&amp;lt;/code&amp;gt;.  Fragments stash unchanged - the role bits are inspected only at consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]).  On out-of-order arrival, build a SACK reply if not rate-limited (per [[#3. Protocol parameters|Section 3]]) and not deduplicated against the previous &amp;lt;code&amp;gt;(rcv_cr.lwe, n_blocks)&amp;lt;/code&amp;gt; pair; D-SACK reports always bypass the dedup.  If both rate-limit and dedup suppress the reply, neither SACK nor delayed-ACK fires (the sender picks up the gap on its next ACK).  On in-order arrival, arm the delayed-ACK timer.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;code&amp;gt;drop_packet&amp;lt;/code&amp;gt; exit&lt;br /&gt;
:Releases the per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;), then calls &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; synchronously after the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt; release to surface any pending cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in [[#16. Stream-mode flows|Section 16]].  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields &amp;lt;code&amp;gt;-EAGAIN&amp;lt;/code&amp;gt;; an oversized run yields &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt; (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring ([[#7.2. Fragmentation and reassembly|Section 7.2]] skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt;, so &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via &amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt; at flow allocation,&lt;br /&gt;
which suppresses &amp;lt;code&amp;gt;frcti&amp;lt;/code&amp;gt; creation.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_pdu_ready&amp;lt;/code&amp;gt; is the no-advance peek used by &amp;lt;code&amp;gt;fevent&amp;lt;/code&amp;gt; (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the &amp;lt;code&amp;gt;poll(2)&amp;lt;/code&amp;gt;-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at &amp;lt;code&amp;gt;rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt;; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and &amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt; is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (&amp;lt;code&amp;gt;flow_write_frag&amp;lt;/code&amp;gt;).  An SDU larger than&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - PCI)&amp;lt;/code&amp;gt; is split into &amp;lt;code&amp;gt;ceil(count / (frag_mtu - PCI))&amp;lt;/code&amp;gt;&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a per-fragment role flag pair ([[#1.2. Flag bits|Section 1.2]]).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! i !! Role&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=0&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;i=n-1&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| else || &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (&amp;lt;code&amp;gt;off &amp;amp;gt; 0&amp;lt;/code&amp;gt;) or&lt;br /&gt;
the underlying error (&amp;lt;code&amp;gt;off == 0&amp;lt;/code&amp;gt;).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (&amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into &amp;lt;code&amp;gt;rq[seqno]&amp;lt;/code&amp;gt; unchanged; role bits&lt;br /&gt;
are read only at consume time.  &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;, called from&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_consume&amp;lt;/code&amp;gt;, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;base = rcv_cr.rwe - RQ_SIZE&amp;lt;/code&amp;gt; (equal to &amp;lt;code&amp;gt;rcv_cr.lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
only when no partial run is in progress; during a partial run &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
has already advanced past &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Outcome !! Cause&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DELIVER (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]=SOLE&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;rq[base]=FIRST&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; follows in slots &amp;lt;code&amp;gt;[base+1..base+n-1]&amp;lt;/code&amp;gt; with all intermediate roles in &amp;lt;code&amp;gt;{MID,FIRST,LAST}&amp;lt;/code&amp;gt; contiguous.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DROP (n)&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;LAST&amp;lt;/code&amp;gt; without a preceding &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;n=1&amp;lt;/code&amp;gt;); a &amp;lt;code&amp;gt;FIRST..[non-LAST]..new-FIRST&amp;lt;/code&amp;gt; or new-&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; mid-run (drop the broken prefix with &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt; = run length minus 1, so the new &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; stays); or, on best-effort flows, a gap at &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; later in the ring (drop up to the new run start).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;rq[base]&amp;lt;/code&amp;gt; absent or &amp;lt;code&amp;gt;FIRST..[non-LAST]&amp;lt;/code&amp;gt; with no later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; in the ring (FRTX waits for retx; best-effort waits for arrival).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DELIVER&amp;lt;/code&amp;gt; triggers &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;: a scatter-gather &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; of the &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;&lt;br /&gt;
consecutive fragments at &amp;lt;code&amp;gt;rq[base..base+n-1]&amp;lt;/code&amp;gt; directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (&amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;) is&lt;br /&gt;
released and &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; advances by &amp;lt;code&amp;gt;n&amp;lt;/code&amp;gt;.  &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; &amp;lt;code&amp;gt;frag_gather&amp;lt;/code&amp;gt;&lt;br /&gt;
only restores the fixed-width invariant &amp;lt;code&amp;gt;rwe == lwe + RQ_SIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; advances &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; past the broken prefix (releasing the &amp;lt;code&amp;gt;spb&amp;lt;/code&amp;gt;s)&lt;br /&gt;
and pulls &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt;.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;amp;gt; &amp;lt;code&amp;gt;max_rcv_sdu&amp;lt;/code&amp;gt;, sum&lt;br /&gt;
&amp;amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with &amp;lt;code&amp;gt;-EMSGSIZE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt;.&lt;br /&gt;
On best-effort flows the gap is permanent, so &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt;&lt;br /&gt;
scans forward in the ring for the next &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt;; if one is&lt;br /&gt;
visible within &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;, it returns &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for the broken prefix and&lt;br /&gt;
the consume loop retries at the new &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt;.  Memory hold is bounded&lt;br /&gt;
by &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; per SDU)&lt;br /&gt;
see no extra wait: any later &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
[[#15. Heritage and adopted techniques|Section 15]]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer): upper bound on ACK delay.  An ACK for a received DATA packet MUST be emitted within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; of receipt; an attempt to send an ACK after the a-timer has expired is suppressed (the sender&#039;s RTO is already in motion).&lt;br /&gt;
* &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; (r-timer): upper bound on retransmission.  A given DATA packet MUST NOT be retransmitted after &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; has elapsed since its first send (&amp;lt;code&amp;gt;t0&amp;lt;/code&amp;gt;); when the bound is hit, the flow is declared down (raising the Ouroboros asynchronous flow condition &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt;, which marks the flow dead to both endpoints) rather than retransmitted again.&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; owns one &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt;, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
;RTO timer&lt;br /&gt;
:On fire (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;), re-emit with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;, mark &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-line (HoL) slot only) bump &amp;lt;code&amp;gt;rto_mul&amp;lt;/code&amp;gt; up to &amp;lt;code&amp;gt;MAX_RTO_MUL&amp;lt;/code&amp;gt;.  Wheel deadline is &amp;lt;code&amp;gt;t_send + (rto &amp;amp;lt;&amp;amp;lt; rto_mul)&amp;lt;/code&amp;gt;.  Re-armed unless consumed.  The RTO timer also clears &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; (re-arming fast-retransmit eligibility), resets &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; to 1 on a HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; if its &amp;lt;code&amp;gt;frct_tx&amp;lt;/code&amp;gt; call fails.&lt;br /&gt;
&lt;br /&gt;
;r-timer guard&lt;br /&gt;
:Before any retransmit attempt, check &amp;lt;code&amp;gt;(now - t0)&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;.  If exceeded, the slot is no longer eligible for retransmit.  Only the RTO timer (&amp;lt;code&amp;gt;rxm_due&amp;lt;/code&amp;gt;) treats r-timer expiry as terminal: it marks the flow &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; (peer unreachable).  Fast-retransmit, SACK-driven retransmit, and NACK-driven head-of-line re-emit silently skip aged-out slots and defer the flow-down decision to the next RTO fire.&lt;br /&gt;
&lt;br /&gt;
;Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
:On a non-advancing cumulative ACK with the scoreboard advanced, fire one fast retransmit when EITHER (a) the head-of-line slot&#039;s latest send is older than the RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; ([[#3. Protocol parameters|Section 3]]) and not yet aged out, OR (b) the SACK &amp;lt;code&amp;gt;dup-thresh&amp;lt;/code&amp;gt; count above &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; reaches &amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; (= 3, RFC 8985 sec. 6.2 step 4).  Fires at most once per non-advancing cumulative-ACK value, gated by &amp;lt;code&amp;gt;rack_fired_lwe&amp;lt;/code&amp;gt; (the &amp;lt;code&amp;gt;snd_cr.lwe&amp;lt;/code&amp;gt; at which fast-retransmit last fired).  Set &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt; on the slot (one-shot per-slot gate) and enter NewReno-style careful recovery (see NewReno below in this section).&lt;br /&gt;
:The RACK reorder window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; uses the RFC 8985 sec. 6.2 form &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor.  Before the first RTT sample seeds &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; falls back to &amp;lt;code&amp;gt;MIN(reo_wnd_mult * SRTT / 4, SRTT)&amp;lt;/code&amp;gt;, still floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt; (consistent with the windowed-minimum fallback described in [[#12. RTT estimation|Section 12]]).  &amp;lt;code&amp;gt;min_rtt&amp;lt;/code&amp;gt; is a windowed minimum over the last &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; = 5 min of RTT samples (matches the Linux &amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt; default) so a route change to a longer path eventually re-anchors the reorder window without relying on &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; growth alone.&lt;br /&gt;
&lt;br /&gt;
;SACK-driven retransmit&lt;br /&gt;
:For each gap below &amp;lt;code&amp;gt;hi_sacked&amp;lt;/code&amp;gt; whose slot is (1) still owned, (2) not already &amp;lt;code&amp;gt;SND_FAST_RXM&amp;lt;/code&amp;gt;, (3) not aged out past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, and (4) either outside the RACK window &amp;lt;code&amp;gt;R&amp;lt;/code&amp;gt; OR with &amp;lt;code&amp;gt;dup_thresh &amp;amp;gt;= DUP_THRESH&amp;lt;/code&amp;gt; (same hybrid as fast-retransmit, see [[#6.2. Locked main path|Section 6.2]]), re-emit.  Each SACK-driven retransmit re-arms a fresh &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; so a lost retransmit can still be recovered by its own RTO timer.&lt;br /&gt;
&lt;br /&gt;
;NewReno&lt;br /&gt;
:On entry, &amp;lt;code&amp;gt;recovery_high = snd_cr.seqno + RTT_QUARANTINE&amp;lt;/code&amp;gt;.  Exit when &amp;lt;code&amp;gt;ackno &amp;amp;gt;= recovery_high&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ackno == snd_cr.seqno&amp;lt;/code&amp;gt; (the latter means everything sent has been acknowledged).  &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; also clears recovery.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds&lt;br /&gt;
(&amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;), so a receiver can detect &amp;quot;stale data&lt;br /&gt;
run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the&lt;br /&gt;
receiver-driven nudge that asks the sender to re-transmit the head&lt;br /&gt;
of the run.&lt;br /&gt;
&lt;br /&gt;
;Send (&amp;lt;code&amp;gt;frcti_nack_snd&amp;lt;/code&amp;gt;, called by &amp;lt;code&amp;gt;frcti_rcv&amp;lt;/code&amp;gt; when &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;FRCT_INACT_NEED_NACK&amp;lt;/code&amp;gt;)&lt;br /&gt;
:When an incoming DATA packet has no DRF and rcv-side activity is older than &amp;lt;code&amp;gt;rcv_cr.inact&amp;lt;/code&amp;gt;, the receiver emits a bare packet with &amp;lt;code&amp;gt;flags = FRCT_NACK&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;seqno = arrival_seqno - 1&amp;lt;/code&amp;gt; (informational only, not consulted by the receive handler).  The cooldown in [[#3. Protocol parameters|Section 3]] rate-limits the burst.  Non-DATA non-DRF arrivals bypass &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt; entirely; non-DATA DRF still rebases via the DRF branch.&lt;br /&gt;
&lt;br /&gt;
;Receive (&amp;lt;code&amp;gt;frcti_nack_rcv&amp;lt;/code&amp;gt;)&lt;br /&gt;
:Dispatched in the early-exit branch ([[#6.1. Early-exit dispatch|Section 6.1]]), before &amp;lt;code&amp;gt;rcv_inact_check&amp;lt;/code&amp;gt;.  The sender copies the head-of-line (HoL) &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; packet, marks the slot &amp;lt;code&amp;gt;SND_RTX | SND_FAST_RXM&amp;lt;/code&amp;gt; (Karn-suppress next ACK, one-shot fast-rxm gate), sets &amp;lt;code&amp;gt;rtt_lwe = snd_cr.lwe + 1&amp;lt;/code&amp;gt;, and re-emits via &amp;lt;code&amp;gt;fast_rxm_send&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt; and a refreshed &amp;lt;code&amp;gt;ackno&amp;lt;/code&amp;gt;.  The original &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left armed - the NACK emit is additive to the normal retransmit machinery, not a replacement.  No-op if nothing is in flight, the HoL slot has aged past &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt;, or the HoL &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt; pointer has been cleared by SACK or RACK.&lt;br /&gt;
&lt;br /&gt;
NACK serves two roles:&lt;br /&gt;
&lt;br /&gt;
# Lost first-of-run (DRF) packet recovery.  Required.  Until the DRF packet arrives, the receiver cannot rebase its window, so any subsequent in-flight packets look stale to the receiver.  The NACK fires the moment the second packet arrives at a stale receiver, telling the sender to re-emit the HoL (DRF) packet at NACK-cooldown latency rather than waiting for the initial RTO (which is the configured default until &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded by the first probe round-trip).&lt;br /&gt;
# General loss-recovery accelerator.  When loss is detected receiver-first, the NACK skips one RTO of latency relative to waiting for the sender&#039;s RTO to fire.&lt;br /&gt;
&lt;br /&gt;
In both cases the existing &amp;lt;code&amp;gt;rxm_entry&amp;lt;/code&amp;gt; and its RTO timer are left&lt;br /&gt;
armed, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is &amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet ([[#1.3. SACK payload|Section 1.3]]) whose payload lists&lt;br /&gt;
&#039;&#039;present&#039;&#039; blocks above &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per [[#3. Protocol parameters|Section 3]] and suppressed when&lt;br /&gt;
neither &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt; of an&lt;br /&gt;
otherwise normal SACK frame (see [[#1.3. SACK payload|Section 1.3]] for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
* DATA arrival with &amp;lt;code&amp;gt;seqno &amp;amp;lt; rcv_cr.lwe&amp;lt;/code&amp;gt;, both wire-dup (no RXM, &amp;lt;code&amp;gt;is_dup_data&amp;lt;/code&amp;gt; path) and retransmit (RXM, post-FC branch) (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
* &amp;lt;code&amp;gt;rq_accept&amp;lt;/code&amp;gt; conflict, slot already occupied in &amp;lt;code&amp;gt;[lwe, rwe)&amp;lt;/code&amp;gt; (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal &amp;lt;code&amp;gt;ack_snd&amp;lt;/code&amp;gt; path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per [[#3. Protocol parameters|Section 3]]&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;, (2) rcv side is inactive (older than &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt;), or (3) the&lt;br /&gt;
sender just sent within &amp;lt;code&amp;gt;TICTIME&amp;lt;/code&amp;gt;.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; in every FC field.  The sender treats&lt;br /&gt;
its &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt; as the absolute right edge: when&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt;= snd_cr.rwe&amp;lt;/code&amp;gt; the window is closed and &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt;&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence &amp;lt;code&amp;gt;DELT_RDV&amp;lt;/code&amp;gt;); the receiver replies with&lt;br /&gt;
a bare FC packet (&amp;lt;code&amp;gt;ackno = 0&amp;lt;/code&amp;gt;) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is clamped to &amp;lt;code&amp;gt;lwe + RQ_SIZE&amp;lt;/code&amp;gt; on receipt and MUST NOT shrink:&lt;br /&gt;
a backward &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is silently clamped to the current &amp;lt;code&amp;gt;snd_cr.rwe&amp;lt;/code&amp;gt;;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes ([[#1.4. RTTP payload|Section 1.4]]) carry a 32-bit &amp;lt;code&amp;gt;probe_id&amp;lt;/code&amp;gt; (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of &amp;lt;code&amp;gt;RTTP_RING&amp;lt;/code&amp;gt; in-flight probes is&lt;br /&gt;
kept; an echo whose &amp;lt;code&amp;gt;(id, nonce)&amp;lt;/code&amp;gt; doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to &amp;lt;code&amp;gt;RTT_CLAMP_MUL * srtt&amp;lt;/code&amp;gt;&lt;br /&gt;
(compile-time &amp;lt;code&amp;gt;RTT_CLAMP_MUL = 16&amp;lt;/code&amp;gt;) once &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is seeded; the first&lt;br /&gt;
cold-probe sample feeds &amp;lt;code&amp;gt;rtt_update&amp;lt;/code&amp;gt; raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
;Cold (no &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; yet)&lt;br /&gt;
:the receive path arms at most one probe per 100 ms via &amp;lt;code&amp;gt;frcti_rcv_probe&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;PROBE_DUE_COLD&amp;lt;/code&amp;gt;); arming requires an incoming packet.  Active send-path arming bails while &amp;lt;code&amp;gt;srtt == 0&amp;lt;/code&amp;gt;.&lt;br /&gt;
;Warm (&amp;lt;code&amp;gt;rtt_probe_arm&amp;lt;/code&amp;gt;, called from &amp;lt;code&amp;gt;frcti_snd&amp;lt;/code&amp;gt;)&lt;br /&gt;
:outstanding data (&amp;lt;code&amp;gt;snd_cr.seqno &amp;amp;gt; snd_cr.lwe&amp;lt;/code&amp;gt;), AND at least &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_rcv_rtt&amp;lt;/code&amp;gt; (last RTT receive of any kind), AND at least &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; since &amp;lt;code&amp;gt;t_snd_probe&amp;lt;/code&amp;gt; (last probe emit).&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator&lt;br /&gt;
(&amp;lt;code&amp;gt;FRCT_LINUX_RTT_ESTIMATOR&amp;lt;/code&amp;gt;, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the &amp;lt;code&amp;gt;2 * srtt&amp;lt;/code&amp;gt; floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per [[#3. Protocol parameters|Section 3]].&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (&amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;rtt_sample_eligible&amp;lt;/code&amp;gt;), beyond&lt;br /&gt;
the cum-ACK advance gate in &amp;lt;code&amp;gt;frcti_ack_rcv&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno &amp;amp;gt; lwe&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;ackno &amp;amp;lt;= seqno&amp;lt;/code&amp;gt;), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry &amp;lt;code&amp;gt;FRCT_RXM&amp;lt;/code&amp;gt;; HoL slot&#039;s &amp;lt;code&amp;gt;SND_RTX&amp;lt;/code&amp;gt; bit clear; slot&#039;s &amp;lt;code&amp;gt;rxm&amp;lt;/code&amp;gt;&lt;br /&gt;
pointer non-NULL (not SACK-consumed); &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; not below the &amp;lt;code&amp;gt;rtt_lwe&amp;lt;/code&amp;gt;&lt;br /&gt;
fence; &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds &amp;lt;code&amp;gt;RACK.min_RTT&amp;lt;/code&amp;gt; (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than &amp;lt;code&amp;gt;MIN_RTT_WIN_NS&amp;lt;/code&amp;gt; (5 min, matches Linux&lt;br /&gt;
&amp;lt;code&amp;gt;tcp_min_rtt_wlen&amp;lt;/code&amp;gt;) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; after at most one window).  Seeded from&lt;br /&gt;
&amp;lt;code&amp;gt;rtt_hint&amp;lt;/code&amp;gt; at &amp;lt;code&amp;gt;rtt_init&amp;lt;/code&amp;gt;; 0 acts as the unset sentinel and the base&lt;br /&gt;
in &amp;lt;code&amp;gt;rack_reorder_window&amp;lt;/code&amp;gt; falls back from &amp;lt;code&amp;gt;min_RTT&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt; (so&lt;br /&gt;
&amp;lt;code&amp;gt;R = mult * SRTT/4&amp;lt;/code&amp;gt;, capped at &amp;lt;code&amp;gt;SRTT&amp;lt;/code&amp;gt;, floored at &amp;lt;code&amp;gt;MIN_REORDER_NS&amp;lt;/code&amp;gt;)&lt;br /&gt;
until the first sample.  See [[#6.2. Locked main path|Section 6.2]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;code&amp;gt;qs.timeout &amp;amp;gt; 0&amp;lt;/code&amp;gt; a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses &amp;lt;code&amp;gt;rcv_cr.act&amp;lt;/code&amp;gt; for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;deadline = min(snd_act + qs.timeout/4, rcv_act + qs.timeout)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to &amp;lt;code&amp;gt;now + qs.timeout/4&amp;lt;/code&amp;gt; if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (&amp;lt;code&amp;gt;ka_snd&amp;lt;/code&amp;gt;) the peer-dead test&lt;br /&gt;
uses &amp;lt;code&amp;gt;max(rcv_cr.act, t_ka_rcv)&amp;lt;/code&amp;gt; so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;code&amp;gt;now - max(rcv_cr.act, t_ka_rcv) &amp;amp;gt; qs.timeout&amp;lt;/code&amp;gt;, mark the flow &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; and notify the per-process flow-event set (&amp;lt;code&amp;gt;proc.fqset&amp;lt;/code&amp;gt;) with &amp;lt;code&amp;gt;FLOW_PEER&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Else if &amp;lt;code&amp;gt;snd_idle &amp;amp;gt; qs.timeout/4&amp;lt;/code&amp;gt;, emit a bare &amp;lt;code&amp;gt;KA | ACK&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;ackno = rcv_cr.lwe&amp;lt;/code&amp;gt;) and re-arm.&lt;br /&gt;
* Else just re-arm.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises &amp;lt;code&amp;gt;ACL_FLOWDOWN&amp;lt;/code&amp;gt; on both (route is&lt;br /&gt;
broken); keepalive raises &amp;lt;code&amp;gt;ACL_FLOWPEER&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps &amp;lt;code&amp;gt;tx_rb&amp;lt;/code&amp;gt; usable) -&lt;br /&gt;
distinct ACLs.  &amp;lt;code&amp;gt;qs.timeout == 0&amp;lt;/code&amp;gt; disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt; computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when &amp;lt;code&amp;gt;rcv_cr.lwe != rcv_cr.seqno&amp;lt;/code&amp;gt; (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FRCTFLINGER&amp;lt;/code&amp;gt; is honoured only when &amp;lt;code&amp;gt;snd_cr.lwe &amp;amp;lt; edge&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;edge =&lt;br /&gt;
snd_fin_seqno&amp;lt;/code&amp;gt; after FIN has been sent in stream mode and&lt;br /&gt;
&amp;lt;code&amp;gt;snd_cr.seqno&amp;lt;/code&amp;gt; otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;&#039;s &amp;lt;code&amp;gt;while (FRCTI_LINGERING)&amp;lt;/code&amp;gt; loop, not in&lt;br /&gt;
&amp;lt;code&amp;gt;frcti_dealloc&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  &amp;lt;code&amp;gt;flow_write&amp;lt;/code&amp;gt; pumps &amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; on every call (via&lt;br /&gt;
&amp;lt;code&amp;gt;flow_wait_window&amp;lt;/code&amp;gt; -&amp;amp;gt; &amp;lt;code&amp;gt;flow_drain_rx_nb&amp;lt;/code&amp;gt;) and additionally blocks on&lt;br /&gt;
&amp;lt;code&amp;gt;rx_rb&amp;lt;/code&amp;gt; when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after &amp;lt;code&amp;gt;t_mpl + a + r&amp;lt;/code&amp;gt; of silence), the DRF marker, and the&lt;br /&gt;
&amp;lt;code&amp;gt;t_mpl&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_a&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;t_r&amp;lt;/code&amp;gt; timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified &amp;lt;code&amp;gt;flow_alloc(name, qos, ...)&amp;lt;/code&amp;gt; primitive and its&lt;br /&gt;
multi-axis QoS-cube argument ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! FRCP mechanism !! Heritage !! Reference / note&lt;br /&gt;
|-&lt;br /&gt;
| Random new &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;seqno_rotate&amp;lt;/code&amp;gt; || TCP ISN || RFC 6528 (Gont &amp;amp;amp; Bellovin, 2012).  QUIC PN-space reset (RFC 9000 sec. 12.3) is a structural analogue.&lt;br /&gt;
|-&lt;br /&gt;
| Cumulative ACK, left-window-edge advance || TCP || RFC 793 / RFC 9293&lt;br /&gt;
|-&lt;br /&gt;
| Receive window with non-shrink rule || TCP || RFC 793 sec. 3.7 / RFC 9293 sec. 3.8.6; RFC 1122 sec. 4.2.2.16 for the explicit non-shrink prohibition&lt;br /&gt;
|-&lt;br /&gt;
| Modular &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; arithmetic (&amp;lt;code&amp;gt;before&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;after&amp;lt;/code&amp;gt; helpers) || TCP || RFC 793 sec. 3.3 / RFC 9293 sec. 3.4&lt;br /&gt;
|-&lt;br /&gt;
| Selective ACK block list || TCP || RFC 2018 (Mathis et al., 1996).  Encoded as a typed FRCP packet rather than a TCP option, so framing is closer to QUIC ACK frames.  D-SACK (RFC 2883) carried in-band as &amp;lt;code&amp;gt;block[0]&amp;lt;/code&amp;gt;; see [[#1.3. SACK payload|Section 1.3]].&lt;br /&gt;
|-&lt;br /&gt;
| NewReno-careful recovery with &amp;lt;code&amp;gt;recovery_high&amp;lt;/code&amp;gt; gate || TCP || RFC 6582 (Henderson et al., 2012); QUIC builds on the same model in RFC 9002 sec. 7.3.2.  Cwnd half absent (CC in IPCP).&lt;br /&gt;
|-&lt;br /&gt;
| RACK reordering window for fast retransmit || TCP || RFC 8985 (Cheng et al., 2021).  FRCP &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; with a &amp;lt;code&amp;gt;MIN_REORDER_NS = 250 us&amp;lt;/code&amp;gt; floor against &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; collapse; matches RFC 8985 sec. 6.2 and Linux &amp;lt;code&amp;gt;tcp_rack_reo_wnd&amp;lt;/code&amp;gt;.  DSACK-driven &amp;lt;code&amp;gt;reo_wnd_mult&amp;lt;/code&amp;gt; (sec. 6.2 step 4) is adopted; see [[#1.3. SACK payload|Section 1.3]] for the wire encoding.  The hybrid RACK-or-&amp;lt;code&amp;gt;DUP_THRESH&amp;lt;/code&amp;gt; trigger from RFC 8985 sec. 6.2 step 4 is adopted ([[#8. Retransmission|Section 8]]).  QUIC&#039;s analogue in RFC 9002 sec. 6.1.2 uses &amp;lt;code&amp;gt;max(srtt, latest_rtt)&amp;lt;/code&amp;gt; as the base.&lt;br /&gt;
|-&lt;br /&gt;
| Karn&#039;s algorithm: no RTT sample on retransmits, RTO-collapse freeze || TCP || Karn &amp;amp;amp; Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, SIGCOMM 1987; RFC 6298 sec. 3.&lt;br /&gt;
|-&lt;br /&gt;
| RTO formula &amp;lt;code&amp;gt;RTO = max(RTO_MIN, srtt + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt; || TCP || RFC 6298 (Paxson et al., 2011).  &amp;lt;code&amp;gt;RTO_MIN&amp;lt;/code&amp;gt; = 5 ms is below RFC 6298 sec. 2.4&#039;s 1 s SHOULD-floor - a recursive-layer choice.&lt;br /&gt;
|-&lt;br /&gt;
| Linux asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; estimator (default) || Linux kernel || &amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt;; the &amp;lt;code&amp;gt;if(delta&amp;amp;lt;0) m&amp;amp;gt;&amp;amp;gt;=3&amp;lt;/code&amp;gt; dampening is a kernel divergence from RFC 6298.  RFC 6298 EWMA available behind a compile flag.&lt;br /&gt;
|-&lt;br /&gt;
| Delayed ACK with rate suppression || TCP || RFC 813 (Clark, 1982); RFC 1122 sec. 4.2.3.2; RFC 5681 sec. 4.2.  Single-deadline coalescing rather than &amp;quot;ack-every-other-segment&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| Zero-window-probe / persist-timer analogue (RDVS) || TCP || RFC 1122 sec. 4.2.2.17 / RFC 9293 sec. 3.8.6.1.  RDVS solicits an FC reply, distinct from QUIC &amp;lt;code&amp;gt;DATA_BLOCKED&amp;lt;/code&amp;gt; (RFC 9000 sec. 19.12), which is one-way notification.  &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; give-up departs from TCP.&lt;br /&gt;
|-&lt;br /&gt;
| Multiplexed control on a single PCI || SCTP / QUIC || SCTP chunk bundling (RFC 9260 sec. 6.10); QUIC frame multiplexing (RFC 9000 sec. 12.4).  Cleaner fit than TCP&#039;s separate-flag-bits design.&lt;br /&gt;
|-&lt;br /&gt;
| ACK ranges as multiple discontiguous acked blocks || QUIC || QUIC ACK frame (RFC 9000 sec. 19.3).  FRCP SACK is conceptually QUIC-frame-shaped even though encoded as absolute &amp;lt;code&amp;gt;[start,end]&amp;lt;/code&amp;gt; pairs.&lt;br /&gt;
|-&lt;br /&gt;
| Nonce-authenticated active RTT / liveness probing (RTTP) || QUIC &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;PATH_RESPONSE&amp;lt;/code&amp;gt; (RFC 9000 sec. 8.2, sec. 19.17, sec. 19.18).  WebRTC ICE consent-freshness (RFC 7675) is the same pattern.  QUIC&#039;s nonce is 8 octets; FRCP chooses 16.&lt;br /&gt;
|-&lt;br /&gt;
| Probing distinct from keepalive || QUIC || KA timer answers &amp;quot;peer alive?&amp;quot;, RTTP answers &amp;quot;path measurable?&amp;quot;, as in QUIC PING (RFC 9000 sec. 19.2) vs &amp;lt;code&amp;gt;PATH_CHALLENGE&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Bare KA + ACK keepalive packets || QUIC / SCTP || QUIC PING (RFC 9000 sec. 19.2); SCTP HEARTBEAT / HEARTBEAT-ACK (RFC 9260 sec. 8.3).  SCTP HEARTBEAT also carries an opaque echoed blob, structurally similar to FRCP RTTP.&lt;br /&gt;
|-&lt;br /&gt;
| (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) fragment-role bits ([[#7.2. Fragmentation and reassembly|Section 7.2]]) || SCTP || RFC 9260 sec. 3.3.1 DATA chunk B/E bits encode the same four states (&amp;lt;code&amp;gt;B+E=SOLE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;B-only=FIRST&amp;lt;/code&amp;gt;, neither=&amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;E-only=LAST&amp;lt;/code&amp;gt;).  Each fragment carries its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;/TSN and is independently retransmitted.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-offset reassembly (Sections [[#1.5. Stream PCI extension|1.5]], [[#16. Stream-mode flows|16]]) || QUIC || QUIC STREAM frame (RFC 9000 sec. 19.8) uses Offset + Length varints; FRCP uses fixed 32-bit &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;.  One stream per flow vs QUIC&#039;s many streams multiplexed.&lt;br /&gt;
|-&lt;br /&gt;
| FIN end-of-stream marker (Sections [[#1.2. Flag bits|1.2]], [[#16. Stream-mode flows|16]]) || TCP / QUIC || TCP FIN flag (RFC 9293 sec. 3.1) closes one half of the byte stream; QUIC STREAM frame FIN bit (RFC 9000 sec. 19.8) does the same per stream with an immutable final-size invariance (RFC 9000 sec. 4.5: the final size is fixed once observed).  FRCP&#039;s FIN consumes one packet &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (not one byte of stream space) and is idempotent on the sender side.&lt;br /&gt;
|-&lt;br /&gt;
| Stream byte-credit flow control ([[#16. Stream-mode flows|Section 16]]) || QUIC || &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; (RFC 9000 sec. 4.1, sec. 19.10).  FRCP projects a per-flow byte budget onto the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt;.  Single stream per flow collapses QUIC&#039;s &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.&lt;br /&gt;
|-&lt;br /&gt;
| Header protection (encrypted seqnos) || QUIC || QUIC RFC 9001 sec. 5.4 applies header protection on top of AEAD to mask the packet number.  FRCP&#039;s per-flow AEAD wrap ([[#16. Stream-mode flows|Section 16]]) is wider: it encrypts the entire PCI including &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; because the IPCP below already routes, so no destination connection-ID needs to stay in clear (cf. RFC 9000 sec. 5.2).&lt;br /&gt;
|-&lt;br /&gt;
| Two-bit fragment role polarity || SCTP || The (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) pair follows SCTP B/E (begin = 1 / end = 1) rather than IPv4 MF (RFC 791 sec. 3.2), which has the inverse polarity (MF = 1 means NOT last).&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal reliability / ordering axes ([[#2.2. Service modes (orthogonal axes)|Section 2.2]]) || SCTP || PR-SCTP (RFC 3758, per-message partial reliability) and SCTP DATA U-bit (RFC 9260 sec. 3.3.1, per-message unordered) are the closest precedents for decoupling reliability from ordering; FRCP sets them per-flow rather than per-message.&lt;br /&gt;
|-&lt;br /&gt;
| Orthogonal CRC (&amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt;) || UDP-Lite || RFC 3828 (Larzon et al., 2004) lets the sender pick a per-packet Checksum Coverage and the receiver enforce a locally configured minimum (no in-band negotiation; sec. 3.1, sec. 3.3).  FRCP gates a full CRC trailer on &amp;lt;code&amp;gt;qs.ber == 0&amp;lt;/code&amp;gt; at flow setup.  Contrast TCP / SCTP (mandatory checksum) and QUIC (AEAD subsumes CRC).&lt;br /&gt;
|-&lt;br /&gt;
| Setup-time service negotiation || DCCP / SCTP / QUIC || DCCP Service Codes (RFC 4340 sec. 8.1.2, RFC 5595); SCTP INIT parameters (RFC 9260 sec. 3.3.2); QUIC transport parameters (RFC 9000 sec. 7.4).  All negotiate service properties at connection setup; only RINA&#039;s QoS cube exposes them as an orthogonal vector.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
* Pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]): receiver-driven nudge exploiting &amp;lt;code&amp;gt;snd_cr.inact &amp;amp;gt; rcv_cr.inact&amp;lt;/code&amp;gt;.  Closest analogues are SCTP Gap Ack Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340 sec. 11.4) - both let the receiver describe gaps to the sender, but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
* &amp;lt;code&amp;gt;MAX_RDV&amp;lt;/code&amp;gt; window-probe give-up: neither TCP (persist-timer probes until application or R2 abort, RFC 9293 sec. 3.8.6.1) nor QUIC has an explicit FC-give-up counter.  A recursive-network choice: outer layers can drop the flow.&lt;br /&gt;
* Skip-past-gap reassembly ([[#7.2. Fragmentation and reassembly|Section 7.2]]): SCTP fragments and reassembles every flow regardless of reliability/ordering, using its own per-stream reassembly queue; QUIC fragments via STREAM offsets.  FRCP fragments best-effort flows too, but the receiver drops the broken prefix the moment a later run-start (&amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; role) is visible inside the &amp;lt;code&amp;gt;RQ_SIZE&amp;lt;/code&amp;gt;-wide reorder ring - no IP-frag-style timeout, no SCTP-style explicit abort.  If no later run-start arrives within the ring, &amp;lt;code&amp;gt;frag_run_inspect&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;NOT_READY&amp;lt;/code&amp;gt; and the partial run keeps its slots; the next inspect retries.  The trade-off: a permanently-lost &amp;lt;code&amp;gt;MID&amp;lt;/code&amp;gt; in a long isolated run holds slots until either a later &amp;lt;code&amp;gt;FIRST&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;SOLE&amp;lt;/code&amp;gt; appears in the ring or the writer stops, at which point the slots are reclaimed on flow teardown.&lt;br /&gt;
* Reassembly deferred to consume time ([[#7.2. Fragmentation and reassembly|Section 7.2]]), message mode only (&amp;lt;code&amp;gt;qos.service == SVC_MESSAGE&amp;lt;/code&amp;gt;): SCTP (RFC 9260 sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all hold reassembly state at the receive boundary.  FRCP message-mode leaves fragments in the shared-memory ring until &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; pulls and lands the SDU directly in the caller&#039;s buffer.  Stream mode ([[#16. Stream-mode flows|Section 16]]) uses the standard QUIC-style direct ring placement on receive and does not defer.  The optimisation is enabled by the Shared-Memory Subsystem (SSM) packet-buffer ring (see &amp;lt;code&amp;gt;struct ssm_pk_buff&amp;lt;/code&amp;gt; at [[#1.1. PCI header|Section 1.1]]); the analogue is OS-level scatter-gather I/O (&amp;lt;code&amp;gt;recvmsg+iovec&amp;lt;/code&amp;gt;), not a transport-layer prior art.&lt;br /&gt;
* TLP-equivalent tail-loss recovery (RFC 8985 sec. 7; RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss Probe packet, but the same goal is met implicitly by RACK loss detection ([[#8. Retransmission|Section 8]]) firing on a non-advancing cumulative ACK once the head-of-line slot ages past the RACK reorder window &amp;lt;code&amp;gt;R = MIN(reo_wnd_mult * min_RTT / 4, SRTT)&amp;lt;/code&amp;gt; - well below &amp;lt;code&amp;gt;RTO = max(2 * SRTT, SRTT + (mdev &amp;amp;lt;&amp;amp;lt; MDEV_MUL))&amp;lt;/code&amp;gt;.  A receiver-driven nudge is also available via the pre-DRF NACK ([[#9. Pre-DRF NACK|Section 9]]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
* Slow start, congestion window (cwnd), Additive Increase / Multiplicative Decrease (AIMD), NewReno cwnd inflation.  Congestion control lives in the IPCP CA policies and is driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
* Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC 1122 sec. 4.2.3.4).  (Deferred work, not adopted in the current spec.)&lt;br /&gt;
* TCP Timestamps (RFC 7323) / Protection Against Wrapped Sequences (PAWS) - RTT measurement uses RTTP, not per-segment timestamps.  A peer-supplied timestamp echoed on every ACK lets a malicious peer drive the &amp;lt;code&amp;gt;srtt&amp;lt;/code&amp;gt; estimate arbitrarily low, collapsing the RTO and triggering a self-inflicted retransmit storm.  RTTP confines RTT measurement to nonce-authenticated probe round-trips, where a forged echo is rejected before it can reach the estimator.&lt;br /&gt;
* ECN (Explicit Congestion Notification) response inside FRCP (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
* IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200 sec. 4.5).  Message-mode FRCP relies on the FRCT &amp;lt;code&amp;gt;rq[]&amp;lt;/code&amp;gt; reorder ring keyed by &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; (shared by FRTX and best-effort flows) to put fragments back in order; no separate offset field is needed and no IP-style hole-list reassembly buffer is kept.  Stream-mode FRCP does carry &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte offsets ([[#1.5. Stream PCI extension|Section 1.5]]) for direct ring placement on receive.&lt;br /&gt;
* QUIC STREAM offset+length framing on &#039;&#039;every&#039;&#039; flow (RFC 9000 sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-bit encoding (&amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt;) and skips the offsets; stream-mode FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with &amp;lt;code&amp;gt;qos.service == SVC_STREAM&amp;lt;/code&amp;gt; both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections [[#6. Receive path|6]]-[[#8. Retransmission|8]].&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
&amp;lt;code&amp;gt;(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt; octets (Sections [[#1.1. PCI header|1.1]]&lt;br /&gt;
and [[#1.5. Stream PCI extension|1.5]]).  Each chunk is one DATA packet with its own &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode &amp;lt;code&amp;gt;FFGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LFGM&amp;lt;/code&amp;gt; are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt;&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has &amp;lt;code&amp;gt;FIN&amp;lt;/code&amp;gt;&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in [[#1.2. Flag bits|Section 1.2]]&lt;br /&gt;
(WR-half close, &amp;lt;code&amp;gt;flow_dealloc&amp;lt;/code&amp;gt;, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
&amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; MUST equal &amp;lt;code&amp;gt;[final-byte, final-byte)&amp;lt;/code&amp;gt; (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an &amp;lt;code&amp;gt;snd_fin_sent&amp;lt;/code&amp;gt; guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width &amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt; (octets) at the position&lt;br /&gt;
indicated by &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, with a two-segment &amp;lt;code&amp;gt;memcpy&amp;lt;/code&amp;gt; across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery ([[#6.2. Locked main path|Section 6.2]]) augmented with the packet&#039;s &amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s &amp;lt;code&amp;gt;[start, end)&amp;lt;/code&amp;gt; front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy &amp;lt;code&amp;gt;start == the last-delivered slot&#039;s end&amp;lt;/code&amp;gt;; a slot whose&lt;br /&gt;
&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; does not equal that &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; is silently dropped at delivery time&lt;br /&gt;
(the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt;; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns up to &amp;lt;code&amp;gt;count&amp;lt;/code&amp;gt; octets from the contiguous prefix&lt;br /&gt;
&amp;lt;code&amp;gt;[next, high-water)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; is the byte the application has&lt;br /&gt;
already consumed up to and &amp;lt;code&amp;gt;high-water&amp;lt;/code&amp;gt; is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (&amp;lt;code&amp;gt;next == EOS&amp;lt;/code&amp;gt; byte position), &amp;lt;code&amp;gt;flow_read&amp;lt;/code&amp;gt; returns&lt;br /&gt;
0 (&amp;lt;code&amp;gt;EOF&amp;lt;/code&amp;gt;) - the same shape POSIX &amp;lt;code&amp;gt;read(2)&amp;lt;/code&amp;gt; uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; received-bitmap.  Let &amp;lt;code&amp;gt;per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension)&amp;lt;/code&amp;gt;, the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry ([[#16.1. Send|Section 16.1]]).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(&amp;lt;code&amp;gt;ring_sz&amp;lt;/code&amp;gt;) cannot be overrun: the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; is at most&lt;br /&gt;
&amp;lt;code&amp;gt;rcv_cr.lwe + ring_sz / per_pkt&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt;, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; space.  With one stream per flow there is no &amp;lt;code&amp;gt;MAX_DATA&amp;lt;/code&amp;gt; /&lt;br /&gt;
&amp;lt;code&amp;gt;MAX_STREAM_DATA&amp;lt;/code&amp;gt; distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time &amp;lt;code&amp;gt;rwe&amp;lt;/code&amp;gt; bump with the global non-shrink rule from&lt;br /&gt;
[[#11. Flow control|Section 11]].&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (&amp;lt;code&amp;gt;start&amp;lt;/code&amp;gt; == prior&lt;br /&gt;
&amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when &amp;lt;code&amp;gt;ber == 0&amp;lt;/code&amp;gt; - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
([[#1.1. PCI header|Section 1.1]]).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see [[#1.1. PCI header|Section 1.1]]).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
* Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
* Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
* Comparable to IPsec ESP transport mode (RFC 4303), which similarly authenticates and encrypts the upper-layer header plus payload, and to QUIC packet protection (RFC 9001 sec. 5), with the difference that QUIC must leave the destination connection ID in the clear for routing whereas FRCP relies on the IPCP below for delivery and can therefore encrypt its entire PCI.&lt;br /&gt;
&lt;br /&gt;
Keying granularity.  FRCP runs key exchange (&amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt;) per flow, so&lt;br /&gt;
each &amp;lt;code&amp;gt;flow_alloc&amp;lt;/code&amp;gt; yields independent symmetric keys.  This is&lt;br /&gt;
finer-grained than QUIC (per-connection, RFC 9001, where one&lt;br /&gt;
handshake covers all multiplexed streams) and finer-grained than&lt;br /&gt;
typical IPsec deployment (per-host-pair Security Associations,&lt;br /&gt;
SAs).  Forward secrecy follows from the &amp;lt;code&amp;gt;kex&amp;lt;/code&amp;gt; when an ephemeral&lt;br /&gt;
Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH +&lt;br /&gt;
post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection.  The AEAD layer itself does NOT carry an&lt;br /&gt;
explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec.&lt;br /&gt;
3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the&lt;br /&gt;
&amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt;-space duplicate-suppression in [[#6.2. Locked main path|Section 6.2]] rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates&lt;br /&gt;
the &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; and a replay re-presents an old &amp;lt;code&amp;gt;seqno&amp;lt;/code&amp;gt; that is then&lt;br /&gt;
discarded either as a duplicate (still inside the receive window)&lt;br /&gt;
or as outside the receive window, depending on how far &amp;lt;code&amp;gt;lwe&amp;lt;/code&amp;gt; has&lt;br /&gt;
advanced since the original packet was delivered.  RAW&lt;br /&gt;
(&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;) flows have no FRCP layer and therefore&lt;br /&gt;
no replay protection at the AEAD layer either; deployments that&lt;br /&gt;
need replay rejection on RAW flows MUST provide it at a higher&lt;br /&gt;
layer.&lt;br /&gt;
&lt;br /&gt;
Layering.  The AEAD wrap sits below FRCP on the data path, so&lt;br /&gt;
RAW best-effort flows (&amp;lt;code&amp;gt;qos.service == SVC_RAW&amp;lt;/code&amp;gt;, the UDP-equivalent&lt;br /&gt;
service of [[#2.2. Service modes (orthogonal axes)|Section 2.2]]) inherit the same per-flow integrity +&lt;br /&gt;
confidentiality scope as FRCP-engaged flows - whatever the IPCP&lt;br /&gt;
and FRCP (if any) put on the wire is what the AEAD authenticates.&lt;br /&gt;
No DTLS-equivalent layering is required for confidentiality and&lt;br /&gt;
integrity; replay protection above AEAD is a separate concern as&lt;br /&gt;
noted above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
;[RFC 791]&lt;br /&gt;
:J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791, September 1981.&lt;br /&gt;
;[RFC 793]&lt;br /&gt;
:J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7, RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
;[RFC 813]&lt;br /&gt;
:D. D. Clark, &amp;quot;Window and Acknowledgement Strategy in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
;[RFC 896]&lt;br /&gt;
:J. Nagle, &amp;quot;Congestion Control in IP/TCP Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
;[RFC 1122]&lt;br /&gt;
:R. Braden (ed.), &amp;quot;Requirements for Internet Hosts -- Communication Layers&amp;quot;, STD 3, RFC 1122, October 1989.&lt;br /&gt;
;[RFC 2018]&lt;br /&gt;
:M. Mathis, J. Mahdavi, S. Floyd, A. Romanow, &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018, October 1996.&lt;br /&gt;
;[RFC 2119]&lt;br /&gt;
:S. Bradner, &amp;quot;Key words for use in RFCs to Indicate Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
;[RFC 2883]&lt;br /&gt;
:S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky, &amp;quot;An Extension to the Selective Acknowledgement (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
;[RFC 3758]&lt;br /&gt;
:R. Stewart, M. Ramalho, Q. Xie, M. Tuexen, P. Conrad, &amp;quot;Stream Control Transmission Protocol (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758, May 2004.&lt;br /&gt;
;[RFC 3828]&lt;br /&gt;
:L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828, July 2004.&lt;br /&gt;
;[RFC 4303]&lt;br /&gt;
:S. Kent, &amp;quot;IP Encapsulating Security Payload (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
;[RFC 4340]&lt;br /&gt;
:E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340, March 2006.&lt;br /&gt;
;[RFC 5288]&lt;br /&gt;
:J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois Counter Mode (GCM) Cipher Suites for TLS&amp;quot;, RFC 5288, August 2008.&lt;br /&gt;
;[RFC 5595]&lt;br /&gt;
:G. Fairhurst, &amp;quot;The Datagram Congestion Control Protocol (DCCP) Service Codes&amp;quot;, RFC 5595, September 2009.&lt;br /&gt;
;[RFC 5681]&lt;br /&gt;
:M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
;[RFC 5925]&lt;br /&gt;
:J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
;[RFC 5961]&lt;br /&gt;
:A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;, RFC 5961, August 2010.&lt;br /&gt;
;[RFC 6298]&lt;br /&gt;
:V. Paxson, M. Allman, J. Chu, M. Sargent, &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298, June 2011.&lt;br /&gt;
;[RFC 6528]&lt;br /&gt;
:F. Gont, S. Bellovin, &amp;quot;Defending against Sequence Number Attacks&amp;quot;, RFC 6528, February 2012.  Obsoletes RFC 1948.&lt;br /&gt;
;[RFC 6582]&lt;br /&gt;
:T. Henderson, S. Floyd, A. Gurtov, Y. Nishida, &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
;[RFC 7323]&lt;br /&gt;
:D. Borman, B. Braden, V. Jacobson, R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
;[RFC 7675]&lt;br /&gt;
:M. Perumal, D. Wing, R. Ravindranath, T. Reddy, M. Thomson, &amp;quot;Session Traversal Utilities for NAT (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675, October 2015.&lt;br /&gt;
;[RFC 8174]&lt;br /&gt;
:B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
;[RFC 8200]&lt;br /&gt;
:S. Deering, R. Hinden, &amp;quot;Internet Protocol, Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200, July 2017.&lt;br /&gt;
;[RFC 8439]&lt;br /&gt;
:Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
;[RFC 8446]&lt;br /&gt;
:E. Rescorla, &amp;quot;The Transport Layer Security (TLS) Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
;[RFC 8985]&lt;br /&gt;
:Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha, &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;, RFC 8985, February 2021.&lt;br /&gt;
;[RFC 9000]&lt;br /&gt;
:J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A UDP-Based Multiplexed and Secure Transport&amp;quot;, RFC 9000, May 2021.&lt;br /&gt;
;[RFC 9001]&lt;br /&gt;
:M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
;[RFC 9002]&lt;br /&gt;
:J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss Detection and Congestion Control&amp;quot;, RFC 9002, May 2021.&lt;br /&gt;
;[RFC 9147]&lt;br /&gt;
:E. Rescorla, H. Tschofenig, N. Modadugu, &amp;quot;The Datagram Transport Layer Security (DTLS) Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
;[RFC 9260]&lt;br /&gt;
:R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control Transmission Protocol&amp;quot;, RFC 9260, June 2022.  Obsoletes RFC 4960.&lt;br /&gt;
;[RFC 9293]&lt;br /&gt;
:W. Eddy (ed.), &amp;quot;Transmission Control Protocol (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes RFC 793 and several follow-ons; updates RFC 1122 and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
;[Day08]&lt;br /&gt;
:J. Day, &amp;quot;Patterns in Network Architecture: A Return to Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
;[Grasa15]&lt;br /&gt;
:E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
;[KP87]&lt;br /&gt;
:P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
;[Wat81]&lt;br /&gt;
:R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5, 1981.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
;[Linux-RTT]&lt;br /&gt;
:&amp;lt;code&amp;gt;tcp_rtt_estimator()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;net/ipv4/tcp_input.c&amp;lt;/code&amp;gt; of the Linux kernel, defining the asymmetric &amp;lt;code&amp;gt;mdev&amp;lt;/code&amp;gt; variance update used as FRCP&#039;s default RTT estimator ([[#12. RTT estimation|Section 12]]).  Line-stable browseable copy at https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&lt;br /&gt;
[[Category:Protocols]]&lt;br /&gt;
[[Category:Ouroboros internals]]&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1914</id>
		<title>Ouroboros Protocols</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1914"/>
		<updated>2026-05-17T13:52:13Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Flow and Retransmission Control Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
&lt;br /&gt;
The protocols in Ouroboros are designed with strong adherence to the principles of [https://en.wikipedia.org/wiki/Separation_of_concerns separation of concerns] and [https://en.wikipedia.org/wiki/Separation_of_mechanism_and_policy separation of mechanism and policy] in mind to prevent network ossification and protocol ossification from occuring.&lt;br /&gt;
&lt;br /&gt;
There are 5 core protocols in Ouroboros.&lt;br /&gt;
&lt;br /&gt;
== Data Transfer Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Data Transfer Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Data Transfer Protocol resides in the [[Ouroboros Functional Layering|network forwarding layer]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                      Destination Address                      +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |  Time-to-Live |      QoS      |      ECN      |    PADDING    |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                              EID                              +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                           N + 1 Data                          +&lt;br /&gt;
 .                                                               .&lt;br /&gt;
 .                                                               .&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow and Retransmission Control Protocol ==&lt;br /&gt;
Main page: [[Flow and Retransmission Control Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Flow and Retransmission Control Protocol resides in the [[Ouroboros Functional Layering|application end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&lt;br /&gt;
  flags   - feature/type bitmap (see 1.2).&lt;br /&gt;
  hcs     - CRC-16-CCITT-FALSE Header Check Sequence (HCS) over&lt;br /&gt;
            flags + window + seqno + ackno (+ stream extension when&lt;br /&gt;
            present); the two octets of the hcs field itself are&lt;br /&gt;
            omitted from the CRC input.  Verified on receive before&lt;br /&gt;
            any flag-driven dispatch.&lt;br /&gt;
  window  - receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
  seqno   - per-flow sequence number.&lt;br /&gt;
  ackno   - cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow Allocation Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Flow Allocation Protocol]]&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 *  0                   1                   2                   3&lt;br /&gt;
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                      id (128 bits)                            +    |&lt;br /&gt;
 * |                  Unique flow allocation ID                    |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                     timestamp (64 bits)                       +    |&lt;br /&gt;
 * |                UTC nanoseconds since epoch                    |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |         crt_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                  certificate (variable)                       +    |&lt;br /&gt;
 * |               X.509 certificate, DER encoded                  |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |F|R|     kex_len (14 bits)     |                               |    | Signed&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    | Region&lt;br /&gt;
 * +                 kex_data (variable)                           +    |&lt;br /&gt;
 * |      public key (DER/raw) or ciphertext (KEM)                 |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |       cipher_len (16 bits)    |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    cipher (variable)                          +    |&lt;br /&gt;
 * |               symmetric cipher name (UTF-8)                   |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |        data_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    data (variable)                            +    |&lt;br /&gt;
 * |              Piggybacked application data                     |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |        sig_len (16 bits)      |                               |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +&lt;br /&gt;
 * |                                                               |&lt;br /&gt;
 * +                     signature (variable)                      +&lt;br /&gt;
 * |                  DSA signature over signed region             |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 *&lt;br /&gt;
 * kex_len field bit layout:&lt;br /&gt;
 *   F (bit 15): Format - 0 = X.509 DER, 1 = Raw/Hybrid&lt;br /&gt;
 *   R (bit 14): Role   - 0 = Server encaps, 1 = Client encaps&lt;br /&gt;
 *               (R is ignored for non-KEM algorithms)&lt;br /&gt;
 *   Bits 0-13:  Length (0-16383 bytes)&lt;br /&gt;
 */&lt;br /&gt;
The Flow Allocation Protocol resides in the [[Ouroboros Functional Layering|network end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
== Connection Establishment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Connection Establishment Protocol]]&lt;br /&gt;
&lt;br /&gt;
== Enrollment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Enrolment Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Enrollment protocol is best seen as one of the application protocols for IPCPs.&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1913</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1913"/>
		<updated>2026-05-17T13:51:36Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 1.1. PCI header */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= FRCP - Flow and Retransmission Control Protocol =&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in src/lib/frct.c.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the FRCT_ prefix&lt;br /&gt;
(FRCT_DATA, FRCT_RXM, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in BCP 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  u32, u8       Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
  ns            Nanoseconds.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    before(a, b)  ==  (int32_t)(a - b) &amp;lt; 0&lt;br /&gt;
    after(a, b)   ==  before(b, a)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for ackno / seqno ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    SRTT          Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
    mdev          Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
    EWMA          Exponentially Weighted Moving Average.&lt;br /&gt;
    RTO           Retransmission Timeout, max(RTO_MIN,&lt;br /&gt;
                  srtt + (mdev &amp;lt;&amp;lt; MDEV_MUL)).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols t_a (a-timer, ACK delay) and t_r (r-timer,&lt;br /&gt;
retransmission window) are defined in Section 8; t_mpl (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in Section 2.1 (the inact field)&lt;br /&gt;
with heritage in Section 15.&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except hcs&lt;br /&gt;
are in network byte order; hcs is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place pci-&amp;gt;hcs read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
Section 1.5); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  flags   - feature/type bitmap (see 1.2).&lt;br /&gt;
  hcs     - CRC-16-CCITT-FALSE Header Check Sequence (HCS) over&lt;br /&gt;
            flags + window + seqno + ackno (+ stream extension when&lt;br /&gt;
            present); the two octets of the hcs field itself are&lt;br /&gt;
            omitted from the CRC input.  Verified on receive before&lt;br /&gt;
            any flag-driven dispatch.&lt;br /&gt;
  window  - receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
  seqno   - per-flow sequence number.&lt;br /&gt;
  ackno   - cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see Section 2.2).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    [   PCI + body          ]    -- the FRCP packet&lt;br /&gt;
    [   PCI + body + CRC-32 ]    -- CRC-32 covers the body only (PCI&lt;br /&gt;
                                    is in HCS); appended iff qs.ber&lt;br /&gt;
                                    == 0 on DATA, or on every SACK&lt;br /&gt;
                                    packet&lt;br /&gt;
    [ AEAD-wrap of above    ]    -- iff Authenticated Encryption&lt;br /&gt;
                                    with Associated Data (AEAD) is&lt;br /&gt;
                                    enabled&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - HCS in the PCI covers the header fields on every packet and is&lt;br /&gt;
    verified before any flag-driven dispatch.&lt;br /&gt;
  - The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial&lt;br /&gt;
    0xEDB88320, init 0xFFFFFFFF, xor-out 0xFFFFFFFF) covers the&lt;br /&gt;
    body on DATA when qs.ber == 0 and on every SACK packet; the&lt;br /&gt;
    trailer is written as a raw uint32_t (the same convention as&lt;br /&gt;
    hcs: opaque on the wire as long as both peers run compatible&lt;br /&gt;
    builds).  The PCI is not under the CRC (Cyclic Redundancy&lt;br /&gt;
    Check) because the HCS already protects it.  It is&lt;br /&gt;
    appended before AEAD encryption and therefore rides inside the&lt;br /&gt;
    AEAD wrap when both are active; the AEAD tag (~2^-128 forgery&lt;br /&gt;
    probability) dominates the CRC (~2^-32) for integrity in that&lt;br /&gt;
    mode but the CRC trailer is currently retained.&lt;br /&gt;
  - When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP&lt;br /&gt;
    packet is wrapped with AEAD inside the shared-memory packet&lt;br /&gt;
    buffer (spb, struct ssm_pk_buff); the packet grows by the AEAD&lt;br /&gt;
    overhead, namely a leading nonce / Initialization Vector (IV)&lt;br /&gt;
    of headsz bytes (crypt_get_ivsz) and a trailing authentication&lt;br /&gt;
    tag of tailsz bytes (crypt_get_tagsz).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and&lt;br /&gt;
are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per Section 1.1; bit 0 is the MSB of the&lt;br /&gt;
16-bit flags field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
    | Bit  | Mask   | Name   | Meaning                                |&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
    |   0  | 0x8000 | DATA   | Carries caller payload                 |&lt;br /&gt;
    |   1  | 0x4000 | DRF    | Data Run Flag: start of a fresh run    |&lt;br /&gt;
    |   2  | 0x2000 | ACK    | Acknowledgement: ackno field valid     |&lt;br /&gt;
    |   3  | 0x1000 | NACK   | Negative ACK; seqno = arrival_seqno-1  |&lt;br /&gt;
    |   4  | 0x0800 | FC     | Flow Control: window field valid (rwe) |&lt;br /&gt;
    |   5  | 0x0400 | RDVS   | Rendezvous probe (window-closed)       |&lt;br /&gt;
    |   6  | 0x0200 | FFGM   | First Fragment (role bit 0; see below) |&lt;br /&gt;
    |   7  | 0x0100 | LFGM   | Last Fragment (role bit 1; see below)  |&lt;br /&gt;
    |   8  | 0x0080 | RXM    | Retransmission                         |&lt;br /&gt;
    |   9  | 0x0040 | SACK   | Selective ACK block list in payload    |&lt;br /&gt;
    |  10  | 0x0020 | RTTP   | RTT Probe / echo (payload follows)     |&lt;br /&gt;
    |  11  | 0x0010 | KA     | Keepalive                              |&lt;br /&gt;
    |  12  | 0x0008 | FIN    | End-of-stream marker (stream mode)     |&lt;br /&gt;
    | 13-15|   --   |  --    | Reserved (MUST be zero)                |&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The (FFGM, LFGM) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
    | FFGM LFGM | Role                                            |&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
    |   1   1   | Sole / un-fragmented SDU (begin AND end)        |&lt;br /&gt;
    |   1   0   | First fragment of a multi-fragment SDU          |&lt;br /&gt;
    |   0   0   | Middle fragment                                 |&lt;br /&gt;
    |   0   1   | Last fragment                                   |&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own seqno;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see Section 2.2)&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (qos.service == SVC_STREAM, see Section 16) there are&lt;br /&gt;
no SDU boundaries to encode, so FFGM and LFGM are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (FIN,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(fccntl to FLOWFRDONLY), during linger drain, and at flow_dealloc;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches byte_fin at the FIN&#039;s&lt;br /&gt;
start offset; flow_read returns 0 (end-of-file, EOF) once buffered&lt;br /&gt;
bytes have been drained up to byte_fin.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension (Section 1.5).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the FRCT_ACK | FRCT_FC | FRCT_SACK flag bits set&lt;br /&gt;
(bit numbering per Section 1.1).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then n_blocks pairs of&lt;br /&gt;
32-bit start/end seqnos describing *present* (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
n_blocks &amp;lt;= SACK_MAX_BLOCKS (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by (frag_mtu - PCI - 4) / 8 blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI ackno field (after(start[i], ackno)).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
before() / after() comparators defined in the Notation block.&lt;br /&gt;
Block[0] carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  case 1 (RFC 2883 sec. 4.1.1, full duplicate):&lt;br /&gt;
      before(blocks[0].start, ackno) and ackno - blocks[0].start is&lt;br /&gt;
      within MAX_DSACK_LAG (== RQ_SIZE).  A single duplicate seqno&lt;br /&gt;
      observed below the cumulative ACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  case 2 (RFC 2883 sec. 4.1.2, partial duplicate):&lt;br /&gt;
      blocks[0] is a sub-range of some blocks[i&amp;gt;0] (not exactly&lt;br /&gt;
      equal).  Reports a duplicate of an in-window seqno that the&lt;br /&gt;
      same packet&#039;s remaining SACK blocks already describe as&lt;br /&gt;
      received.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Senders that do not implement D-SACK process block[0] through the&lt;br /&gt;
normal SACK-mark loop and the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (start &amp;lt; snd_cr.lwe clamps to snd_cr.lwe, the inner&lt;br /&gt;
loop then skips k == snd_cr.lwe) and case-2 idempotent (same slots&lt;br /&gt;
NULL&#039;d twice).  D-SACK-aware senders feed the report into the RACK&lt;br /&gt;
reo_wnd_mult scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see Section 8); only non-D-SACK blocks&lt;br /&gt;
count as gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the FRCT_RTTP flag&lt;br /&gt;
set (bit numbering per Section 1.1).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  probe_id - sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
  echo_id  - peer&#039;s probe_id, 0 on outbound probe.&lt;br /&gt;
  nonce    - random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (qos.service == SVC_STREAM) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per Section 1.1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  start - octet offset of the first payload byte in the stream.&lt;br /&gt;
  end   - octet offset one past the last payload byte;&lt;br /&gt;
          end - start equals the on-wire payload length.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat start/end as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with start not equal to the prior packet&#039;s end the&lt;br /&gt;
slot is silently dropped at delivery time (Section 16) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet seqno (this PCI&#039;s seqno field) and a&lt;br /&gt;
separate stream byte position (start/end).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet FRCT_RXM,&lt;br /&gt;
per-slot SND_RTX flags, and a sample-fence rtt_lwe (see Section 2.1&lt;br /&gt;
and Section 12).  FRCP&#039;s fixed-32-bit start/end wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular before()&lt;br /&gt;
/ after() comparators (Section 1.3) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in before()).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps ring_sz at 128 MiB (FRCT_STREAM_RING_SZ_MAX),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform size_t and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    lwe    : u32  snd: oldest unacked seqno (cumulative ACK&lt;br /&gt;
                  boundary as seen by sender);&lt;br /&gt;
                  rcv: next in-order seqno expected&lt;br /&gt;
    rwe    : u32  snd: peer-advertised right window edge;&lt;br /&gt;
                  rcv: locally-advertised right window edge&lt;br /&gt;
    cflags : u8   per-direction feature flags: retransmission&lt;br /&gt;
                  (FRCTFRTX), receiver flow control&lt;br /&gt;
                  (FRCTFRESCNTL), linger-on-close (FRCTFLINGER);&lt;br /&gt;
                  see &amp;lt;ouroboros/fccntl.h&amp;gt;&lt;br /&gt;
    seqno  : u32  snd: next seqno to send;&lt;br /&gt;
                  rcv: force-ACK trigger - set on a stale or dup&lt;br /&gt;
                  DATA so the next ack_snd emits a fresh&lt;br /&gt;
                  cumulative ACK&lt;br /&gt;
    ackno  : u32  snd: outbound ACK-packet seqno counter,&lt;br /&gt;
                  incremented for every ACK-bearing packet (bare&lt;br /&gt;
                  ACK, delayed ACK, SACK); used by wire-dup ACK&lt;br /&gt;
                  detection;&lt;br /&gt;
                  rcv: incoming-ACK dedup tracker&lt;br /&gt;
    act    : ns   last activity (used by inactivity / DRF)&lt;br /&gt;
    inact  : ns   inactivity threshold; sender = 3*mpl + a + r + 1s,&lt;br /&gt;
                  receiver = 2*mpl + a + r + 1s.  mpl is the&lt;br /&gt;
                  Maximum Packet Lifetime (delta-t terminology;&lt;br /&gt;
                  see Section 15); a and r are the FRCT a-timer&lt;br /&gt;
                  and r-timer bounds (see Section 8).  The&lt;br /&gt;
                  asymmetry is load-bearing for pre-DRF NACK&lt;br /&gt;
                  (Section 9).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring snd_slots[RQ_SIZE] keyed by&lt;br /&gt;
(seqno mod RQ_SIZE).  Each slot tracks its retransmit entry (rxm),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: SND_RTX (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and SND_FAST_RXM (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring rcv_slots[RQ_SIZE]&lt;br /&gt;
(referred to as rq[] in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant rwe - lwe &amp;lt;= RQ_SIZE holds: on each consume&lt;br /&gt;
the receiver advances rwe by the consumed count, capping the&lt;br /&gt;
receive window at RQ_SIZE seqno slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable rtt_lwe is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
seqno_rotate (Section 4) to mark the seqno range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same flow_alloc(name, qos, ...) primitive; the qosspec_t passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (SOCK_STREAM / SOCK_DGRAM).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  service   0 = unordered (no FRCP engagement: raw datagrams,&lt;br /&gt;
              no PCI on the wire, UDP-equivalent at this layer)&lt;br /&gt;
            1 = message-ordered (FRCP engaged; SDU boundaries&lt;br /&gt;
              preserved across fragmentation)&lt;br /&gt;
            2 = stream (byte-oriented, no SDU boundaries; FRTX&lt;br /&gt;
              required)&lt;br /&gt;
  loss      0 = lossless service requested: FRTX retransmit&lt;br /&gt;
              machinery engages (Section 8); MUST be 0 for&lt;br /&gt;
              service=2.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
  ber       Bit Error Rate tolerance.&lt;br /&gt;
            0 = error-free service requested: a CRC trailer is&lt;br /&gt;
              appended after the body of DATA packets and verified&lt;br /&gt;
              on receive (added / checked outside the FRCP PCI;&lt;br /&gt;
              see Section 1.1).  Non-zero = peer accepts errors;&lt;br /&gt;
              trailer omitted.  SACK control packets carry a&lt;br /&gt;
              CRC32 trailer regardless of ber; the ber gate&lt;br /&gt;
              applies to DATA only.&lt;br /&gt;
  timeout   Peer-timeout (ms); 0 disables the keepalive timer.&lt;br /&gt;
              Independent of FRCP engagement.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the spb by headsz + tailsz&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see Section 1.1).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by include/ouroboros/qos.h:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
  | Cube            | service | loss | ber | Engaged               |&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
  | qos_raw         |    0    |   1  |   1 | Raw passthrough       |&lt;br /&gt;
  | qos_raw_safe    |    0    |   1  |   0 | Raw + CRC trailer     |&lt;br /&gt;
  | qos_rt          |    1    |   1  |   1 | FRCP, no FRTX, no CRC |&lt;br /&gt;
  | qos_rt_safe     |    1    |   1  |   0 | FRCP, no FRTX, CRC    |&lt;br /&gt;
  | qos_msg         |    1    |   0  |   0 | FRCP + FRTX           |&lt;br /&gt;
  | qos_stream      |    2    |   0  |   0 | FRCP + FRTX, stream   |&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - service == SVC_STREAM (2) requires loss == 0; flow_alloc /&lt;br /&gt;
    flow_accept reject the pair otherwise with -EINVAL.&lt;br /&gt;
  - FRTX requires FRCP engagement (service != SVC_RAW); requesting&lt;br /&gt;
    loss = 0 with service = SVC_RAW is structurally a no-op&lt;br /&gt;
    because no frcti is created.&lt;br /&gt;
  - The QOS_DISABLE_CRC build flag globally forces ber = 1.&lt;br /&gt;
    Note: this flag defaults to ON, so default builds ship with&lt;br /&gt;
    CRC disabled until QOS_DISABLE_CRC is set to OFF.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force ber = 0 when service != SVC_RAW.&lt;br /&gt;
qos_rt has service = SVC_MESSAGE with ber = 1, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS (Section 1.1)&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (service = SVC_MESSAGE, loss &amp;gt; 0) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly (Section 7.2) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
    | Parameter          | Value                  | Role              |&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
    | RQ_SIZE            | compile-time, power of | Slot ring / rcv   |&lt;br /&gt;
    |                    |  2 (default 128)       | window width      |&lt;br /&gt;
    | START_WINDOW       | compile-time, power of | Initial rwe-lwe   |&lt;br /&gt;
    |                    |  2 (default 128)       | after rotate      |&lt;br /&gt;
    | RTO_MIN            | MAX(250 us build-tun-  | RTO floor; also   |&lt;br /&gt;
    |                    |  able, 1&amp;lt;&amp;lt;RXMQ_RES);   | floored at the    |&lt;br /&gt;
    |                    |  per-flow via fccntl   | retransmit-wheel  |&lt;br /&gt;
    |                    |  (FRCTSRTOMIN).        | resolution        |&lt;br /&gt;
    |                    |  Default ~1 ms with    | (~1 ms by         |&lt;br /&gt;
    |                    |  RXMQ_RES=20.          | default).         |&lt;br /&gt;
    | MAX_RTO_MUL        | 20                     | Backoff shift cap |&lt;br /&gt;
    | RACK window R      | MIN(reo_wnd_mult       | Reorder window;   |&lt;br /&gt;
    |                    |  * min_RTT/4, SRTT)    | per RFC 8985      |&lt;br /&gt;
    |                    |  with MIN_REORDER_NS   | sec. 6.2;         |&lt;br /&gt;
    |                    |  = 250 us floor;       | reo_wnd_mult per  |&lt;br /&gt;
    |                    |  reo_wnd_mult scales   | sec. 6.2 step 4   |&lt;br /&gt;
    |                    |  on D-SACK, cap 20     |                   |&lt;br /&gt;
    | MIN_RTT_WIN_NS     | 300 s (5 min, Linux    | min_RTT windowed  |&lt;br /&gt;
    |                    |  tcp_min_rtt_wlen)     | re-anchor         |&lt;br /&gt;
    | REO_WND_MULT_MAX   | 20 (RFC 8985 sec.      | reo_wnd_mult cap  |&lt;br /&gt;
    |                    |  6.2 step 4)           |                   |&lt;br /&gt;
    | REO_DECAY_PKTS     | 16 (RFC 8985 sec.      | Fresh-ACK&#039;d seq   |&lt;br /&gt;
    |                    |  6.2 step 4 /          | count per halving |&lt;br /&gt;
    |                    |  RACK.reo_wnd_persist) |                   |&lt;br /&gt;
    | MAX_DSACK_LAG      | RQ_SIZE                | D-SACK sanity cap |&lt;br /&gt;
    | RTT_QUARANTINE     | 32 (seqno steps)       | NewReno gate pad  |&lt;br /&gt;
    | SACK rate-limit    | SACK_MIN_GAP_NS        | Min SACK gap      |&lt;br /&gt;
    |                    |  (250 us, fixed)       |                   |&lt;br /&gt;
    | SACK_MAX_BLOCKS    | 2048 (wire cap; per-   | Per-SACK block    |&lt;br /&gt;
    |                    |  flow capped at        | cap               |&lt;br /&gt;
    |                    |  (frag_mtu-PCI-4)/8)   |                   |&lt;br /&gt;
    | SACK_RXM_MAX       | 32                     | Per-pass staged   |&lt;br /&gt;
    |                    |                        | retransmit cap    |&lt;br /&gt;
    | DUP_THRESH         | 3 (RFC 8985 default)   | Hybrid fast-rxm   |&lt;br /&gt;
    |                    |                        | trigger (Sec. 8)  |&lt;br /&gt;
    | MDEV_MUL           | 2 (build-tunable via   | mdev shift in     |&lt;br /&gt;
    |                    |  FRCT_RTO_MDEV_-       | RTO = srtt +      |&lt;br /&gt;
    |                    |  MULTIPLIER)           | (mdev &amp;lt;&amp;lt; MDEV_MUL)|&lt;br /&gt;
    | RTTP nonce         | 16 octets              | Echoed verbatim   |&lt;br /&gt;
    | RTTP_RING          | 8                      | In-flight probes  |&lt;br /&gt;
    | RTT clamp          | 16 * srtt              | Probe-sample      |&lt;br /&gt;
    |                    |                        | upper bound       |&lt;br /&gt;
    |                    |                        | (ACK-derived RTT  |&lt;br /&gt;
    |                    |                        | samples gated by  |&lt;br /&gt;
    |                    |                        | Karn / recovery   |&lt;br /&gt;
    |                    |                        | only)             |&lt;br /&gt;
    | Cold-probe cadence | 100 ms (rx-driven;     | Pre-srtt RTTP     |&lt;br /&gt;
    |                    |  see Section 12)       | rate              |&lt;br /&gt;
    | DELT_RDV           | 100 ms                 | RDVS emit cadence |&lt;br /&gt;
    | MAX_RDV            | 1 s                    | RDVS give-up      |&lt;br /&gt;
    | Delayed-ACK fire   | 2 * TICTIME (TICTIME   | Fired after the   |&lt;br /&gt;
    |                    |  = FRCT tick gran-     | first in-order    |&lt;br /&gt;
    |                    |  ularity, default      | DATA arrival;     |&lt;br /&gt;
    |                    |  5 ms; 2*TICTIME       | tick is build-    |&lt;br /&gt;
    |                    |  = 10 ms by default)   | tunable           |&lt;br /&gt;
    | NACK send cooldown | srtt when an srtt      | Pre-DRF NACK      |&lt;br /&gt;
    |                    |  sample exists, else   | rate-limit        |&lt;br /&gt;
    |                    |  100 ms                |                   |&lt;br /&gt;
    | MAX_SDU            | 1 MiB                  | Max reassembled   |&lt;br /&gt;
    |                    |                        | SDU; configurable |&lt;br /&gt;
    |                    |                        | per flow          |&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
headsz / tailsz and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (snd_cr.seqno == snd_cr.lwe).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
snd_cr.inact AND the pipe is empty (snd_cr.seqno == snd_cr.lwe),&lt;br /&gt;
seqno_rotate() rolls a random new seqno before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(now - rcv_cr.act &amp;gt; rcv_cr.inact), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the rq[] slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per Section 3); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    1. If the SDU exceeds (frag_mtu - data_hdr_len), the caller&lt;br /&gt;
       (dev.c) fans it out into ceil(count / (frag_mtu -&lt;br /&gt;
       data_hdr_len)) fragments, each emitted via frcti_snd as its&lt;br /&gt;
       own DATA packet with a per-fragment role (Section 7.2);&lt;br /&gt;
       both FRTX and best-effort flows fragment.  Raw flows (no&lt;br /&gt;
       FRCP engagement, qos.service == SVC_RAW) carry no PCI and&lt;br /&gt;
       return -EMSGSIZE for any SDU larger than one packet at the&lt;br /&gt;
       layer below.  An SDU that fits in a single packet is sent&lt;br /&gt;
       as SOLE.  frcti_snd reserves PCI head room; sets DATA, plus&lt;br /&gt;
       DRF when the pipe is empty (snd_cr.seqno == snd_cr.lwe).&lt;br /&gt;
    2. seqno_rotate() if past sender inactivity and the pipe is&lt;br /&gt;
       empty (Section 4).&lt;br /&gt;
    3. Advertise FC (pci.window = frcti_advert_rwe(frcti), i.e.&lt;br /&gt;
       rcv_cr.rwe clamped to rcv_cr.lwe + ring_seq_cap in stream&lt;br /&gt;
       mode) when the receiver side is recent: now - rcv_cr.act&lt;br /&gt;
       &amp;lt; rcv_cr.inact.&lt;br /&gt;
    4. Reliable mode (FRTX): leave snd_cr.lwe where it is; reset&lt;br /&gt;
       the slot at RQ_SLOT(seqno) (snd_slots[p].time = now,&lt;br /&gt;
       snd_slots[p].flags = 0); queue an rxm_entry (saves a packet&lt;br /&gt;
       copy, arms a wheel timer at now + (rto &amp;lt;&amp;lt; rto_mul)).&lt;br /&gt;
       Piggyback ACK (pci.ackno = rcv_cr.lwe) while the a-timer&lt;br /&gt;
       for the most recent received DATA packet has not yet&lt;br /&gt;
       expired (now - rcv_cr.act &amp;lt;= t_a); on piggyback, set&lt;br /&gt;
       rcv_cr.seqno = rcv_cr.lwe so the next delayed-ACK fire is&lt;br /&gt;
       suppressed.  See Section 8 for t_a / t_r semantics.&lt;br /&gt;
    5. Best-effort mode (no FRTX): advance snd_cr.lwe immediately&lt;br /&gt;
       (snd_cr.lwe = snd_cr.lwe + 1, snd_cr.rwe = snd_cr.lwe +&lt;br /&gt;
       RQ_SIZE); no retransmit state.  No send-side RTT probe is&lt;br /&gt;
       armed in this mode (rtt_probe_arm requires an in-flight&lt;br /&gt;
       seqno, which best-effort never has); the rx-driven cold&lt;br /&gt;
       seeder in frcti_rcv is the only probe path.&lt;br /&gt;
    6. In reliable mode, optionally arm an RTT probe (Section 12).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of frcti_rcv before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - KA   : refresh t_ka_rcv, honour piggybacked ACK.&lt;br /&gt;
  - RTTP : probe (echo back nonce) or echo (verify nonce, sample&lt;br /&gt;
           RTT).&lt;br /&gt;
  - NACK : pre-DRF, sender-side handler.  See Section 9.&lt;br /&gt;
  - RDVS : reply with a bare FC packet (ackno = 0); rdlock only.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow frcti.lock held for writing&lt;br /&gt;
(pthread_rwlock_wrlock) unless noted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  rcv_inact_check&lt;br /&gt;
      Only meaningful when the receive side is stale.  On DRF&lt;br /&gt;
      (Data Run Flag): release rq[] slots, rebase rcv_cr, continue.&lt;br /&gt;
      On stale DATA without DRF: fire a pre-DRF NACK if cooldown&lt;br /&gt;
      allows (Section 9), then discard the packet; on cooldown,&lt;br /&gt;
      drop without sending a NACK (a pending cumulative ACK from&lt;br /&gt;
      drop_packet may still go out).  Non-DATA, non-DRF arrivals&lt;br /&gt;
      bypass rcv_inact_check entirely; pure-DRF stale arrivals fall&lt;br /&gt;
      through after the DRF rebase branch.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  DATA-only act refresh&lt;br /&gt;
      Refresh rcv_cr.act only when FRCT_DATA is set, so that non-DATA&lt;br /&gt;
      packets never block the next DRF rebase.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Wire-dup gate&lt;br /&gt;
      Before flag-driven dispatch, drop wire-duplicate ACKs and&lt;br /&gt;
      wire-duplicate DATA (is_dup_ack / is_dup_data).  The DATA&lt;br /&gt;
      check is bypassed for FRCT_RXM-bearing arrivals so the&lt;br /&gt;
      piggybacked ACK / SACK / FC carried on a retransmitted DATA&lt;br /&gt;
      at an already-ACK&#039;d seqno is still applied; the stale-in-&lt;br /&gt;
      window branch below then drops the packet.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ACK&lt;br /&gt;
      Drop ACKs whose ackno falls outside (snd_cr.lwe, snd_cr.seqno].&lt;br /&gt;
      If ackno == snd_cr.lwe (non-advancing cumulative ACK), drive&lt;br /&gt;
      RACK fast-retransmit consideration (Section 8).  Otherwise&lt;br /&gt;
      advance snd_cr.lwe = ackno, collapse rto_mul to 0 (Karn-gated&lt;br /&gt;
      by SND_RTX on the just-acknowledged slot, the old head-of-&lt;br /&gt;
      line), reset dup_thresh to 0, update t_latest_ack to the&lt;br /&gt;
      send-time of the slot at ackno-1 (consumed by RACK and SACK&lt;br /&gt;
      below), decay reo_wnd_mult per RFC 8985 sec. 6.2 step 4,&lt;br /&gt;
      exit NewReno-careful recovery (see Section 8) on&lt;br /&gt;
      ackno &amp;gt;= recovery_high or ackno == snd_cr.seqno, and feed an&lt;br /&gt;
      RTT sample if eligible (Section 12).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  SACK&lt;br /&gt;
      Walk the block list.  For each block (a present range above&lt;br /&gt;
      lwe) NULL out snd_slots[k].rxm, clear the slot&#039;s per-send&lt;br /&gt;
      flags, and advance t_latest_ack to the latest send-time&lt;br /&gt;
      covered (the Forward Acknowledgement / fack equivalent,&lt;br /&gt;
      Mathis &amp;amp; Mahdavi 1996); the first block whose start&lt;br /&gt;
      clamps to snd_cr.lwe skips this fack update so that a head-&lt;br /&gt;
      of-line clamp does not falsely advance fack.  For un-SACKed&lt;br /&gt;
      gaps below hi_sacked, stage a retransmit per slot that is&lt;br /&gt;
      (1) still owned (rxm != NULL), (2) not already SND_FAST_RXM,&lt;br /&gt;
      (3) not aged out past t_r, and (4) either outside the RACK&lt;br /&gt;
      reorder window R OR with dup_thresh &amp;gt;= DUP_THRESH (the RFC&lt;br /&gt;
      8985 sec. 6.2 hybrid trigger).  Mark the slot SND_FAST_RXM&lt;br /&gt;
      and NULL the rxm at stage time.  Capped at SACK_RXM_MAX&lt;br /&gt;
      staged retransmits per receive pass; what&#039;s left rides the&lt;br /&gt;
      next SACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  FC&lt;br /&gt;
      Bump snd_cr.rwe (clamped to lwe + RQ_SIZE, never shrinks)&lt;br /&gt;
      and mark window open.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  DATA&lt;br /&gt;
      Bounds-check seqno against window.  On stale-dup&lt;br /&gt;
      (seqno &amp;lt; rcv_cr.lwe), set rcv_cr.seqno = seqno to force a&lt;br /&gt;
      fresh ACK on the next ack_snd, then drop.  On accept: both&lt;br /&gt;
      FRTX and best-effort stash the packet-buffer index into&lt;br /&gt;
      rq[seqno mod RQ_SIZE].  Fragments stash unchanged - the role&lt;br /&gt;
      bits are inspected only at consume time (Section 7.2).  On&lt;br /&gt;
      out-of-order arrival, build a SACK reply if not rate-limited&lt;br /&gt;
      (per Section 3) and not deduplicated against the previous&lt;br /&gt;
      (rcv_cr.lwe, n_blocks) pair; D-SACK reports always bypass the&lt;br /&gt;
      dedup.  If both rate-limit and dedup suppress the reply,&lt;br /&gt;
      neither SACK nor delayed-ACK fires (the sender picks up the&lt;br /&gt;
      gap on its next ACK).  On in-order arrival, arm the delayed-&lt;br /&gt;
      ACK timer.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  drop_packet exit&lt;br /&gt;
      Releases the per-packet shared-memory buffer (spb), then&lt;br /&gt;
      calls ack_snd synchronously after the spb release to surface&lt;br /&gt;
      any pending cumulative ACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
flow_read returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
frcti_consume on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in Section 16.  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields -EAGAIN; an oversized run yields -EMSGSIZE (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring (Section 7.2 skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no frcti, so flow_read returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via qos.service == SVC_RAW at flow allocation,&lt;br /&gt;
which suppresses frcti creation.)&lt;br /&gt;
&lt;br /&gt;
frcti_pdu_ready is the no-advance peek used by fevent (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the poll(2)-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at rcv_cr.rwe - RQ_SIZE; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and frcti_consume is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (flow_write_frag).  An SDU larger than&lt;br /&gt;
(frag_mtu - PCI) is split into ceil(count / (frag_mtu - PCI))&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
seqno and a per-fragment role flag pair (Section 1.2).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +------+--------+&lt;br /&gt;
    | i    | Role   |&lt;br /&gt;
    +------+--------+&lt;br /&gt;
    | n=1  | SOLE   |&lt;br /&gt;
    | i=0  | FIRST  |&lt;br /&gt;
    | i=n-1| LAST   |&lt;br /&gt;
    | else | MID    |&lt;br /&gt;
    +------+--------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (off &amp;gt; 0) or&lt;br /&gt;
the underlying error (off == 0).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (-EMSGSIZE).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s seqno flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same seqno&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no rxm state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into rq[seqno] unchanged; role bits&lt;br /&gt;
are read only at consume time.  frag_run_inspect, called from&lt;br /&gt;
frcti_consume, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered seqno base = rcv_cr.rwe - RQ_SIZE (equal to rcv_cr.lwe&lt;br /&gt;
only when no partial run is in progress; during a partial run lwe&lt;br /&gt;
has already advanced past base).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
    | Outcome       | Cause                                       |&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
    | DELIVER (n)   | rq[base]=SOLE (n=1), or rq[base]=FIRST and  |&lt;br /&gt;
    |               | a LAST follows in slots [base+1..base+n-1]  |&lt;br /&gt;
    |               | with all intermediate roles in {MID,FIRST,  |&lt;br /&gt;
    |               | LAST} contiguous.                           |&lt;br /&gt;
    | DROP (n)      | rq[base] is MID or LAST without a preceding |&lt;br /&gt;
    |               | FIRST (n=1); a FIRST..[non-LAST]..new-FIRST |&lt;br /&gt;
    |               | or new-SOLE mid-run (drop the broken prefix |&lt;br /&gt;
    |               | with n = run length minus 1, so the new     |&lt;br /&gt;
    |               | FIRST/SOLE stays); or, on best-effort       |&lt;br /&gt;
    |               | flows, a gap at base with a FIRST/SOLE      |&lt;br /&gt;
    |               | later in the ring (drop up to the new run   |&lt;br /&gt;
    |               | start).                                     |&lt;br /&gt;
    | NOT_READY     | rq[base] absent or FIRST..[non-LAST] with   |&lt;br /&gt;
    |               | no later FIRST/SOLE in the ring (FRTX waits |&lt;br /&gt;
    |               | for retx; best-effort waits for arrival).   |&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
DELIVER triggers frag_gather: a scatter-gather memcpy of the n&lt;br /&gt;
consecutive fragments at rq[base..base+n-1] directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (spb) is&lt;br /&gt;
released and rwe advances by n.  lwe was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; frag_gather&lt;br /&gt;
only restores the fixed-width invariant rwe == lwe + RQ_SIZE.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
DROP advances rwe past the broken prefix (releasing the spbs)&lt;br /&gt;
and pulls lwe up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new base.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;gt; max_rcv_sdu, sum&lt;br /&gt;
&amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with -EMSGSIZE.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and frag_run_inspect returns NOT_READY.&lt;br /&gt;
On best-effort flows the gap is permanent, so frag_run_inspect&lt;br /&gt;
scans forward in the ring for the next FIRST or SOLE; if one is&lt;br /&gt;
visible within RQ_SIZE, it returns DROP for the broken prefix and&lt;br /&gt;
the consume loop retries at the new lwe.  Memory hold is bounded&lt;br /&gt;
by RQ_SIZE; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one SOLE per SDU)&lt;br /&gt;
see no extra wait: any later SOLE makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
Section 15):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - t_a (a-timer): upper bound on ACK delay.  An ACK for a received&lt;br /&gt;
    DATA packet MUST be emitted within t_a of receipt; an attempt&lt;br /&gt;
    to send an ACK after the a-timer has expired is suppressed&lt;br /&gt;
    (the sender&#039;s RTO is already in motion).&lt;br /&gt;
  - t_r (r-timer): upper bound on retransmission.  A given DATA&lt;br /&gt;
    packet MUST NOT be retransmitted after t_r has elapsed since&lt;br /&gt;
    its first send (t0); when the bound is hit, the flow is&lt;br /&gt;
    declared down (raising the Ouroboros asynchronous flow&lt;br /&gt;
    condition ACL_FLOWDOWN, which marks the flow dead to both&lt;br /&gt;
    endpoints) rather than retransmitted again.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX seqno owns one rxm_entry, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  RTO timer&lt;br /&gt;
      On fire (rxm_due), re-emit with FRCT_RXM, mark SND_RTX&lt;br /&gt;
      (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-&lt;br /&gt;
      line (HoL) slot only) bump rto_mul up to MAX_RTO_MUL.  Wheel&lt;br /&gt;
      deadline is t_send + (rto &amp;lt;&amp;lt; rto_mul).  Re-armed unless&lt;br /&gt;
      consumed.  The RTO timer also clears SND_FAST_RXM (re-arming&lt;br /&gt;
      fast-retransmit eligibility), resets reo_wnd_mult to 1 on a&lt;br /&gt;
      HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks&lt;br /&gt;
      the flow ACL_FLOWDOWN if its frct_tx call fails.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  r-timer guard&lt;br /&gt;
      Before any retransmit attempt, check (now - t0) against t_r.&lt;br /&gt;
      If exceeded, the slot is no longer eligible for retransmit.&lt;br /&gt;
      Only the RTO timer (rxm_due) treats r-timer expiry as&lt;br /&gt;
      terminal: it marks the flow ACL_FLOWDOWN (peer unreachable).&lt;br /&gt;
      Fast-retransmit, SACK-driven retransmit, and NACK-driven&lt;br /&gt;
      head-of-line re-emit silently skip aged-out slots and defer&lt;br /&gt;
      the flow-down decision to the next RTO fire.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
      On a non-advancing cumulative ACK with the scoreboard&lt;br /&gt;
      advanced, fire one fast retransmit when EITHER (a) the head-&lt;br /&gt;
      of-line slot&#039;s latest send is older than the RACK reorder&lt;br /&gt;
      window R (Section 3) and not yet aged out, OR (b) the SACK&lt;br /&gt;
      dup-thresh count above snd_cr.lwe reaches DUP_THRESH (= 3,&lt;br /&gt;
      RFC 8985 sec. 6.2 step 4).  Fires at most once per non-&lt;br /&gt;
      advancing cumulative-ACK value, gated by rack_fired_lwe (the&lt;br /&gt;
      snd_cr.lwe at which fast-retransmit last fired).  Set&lt;br /&gt;
      SND_FAST_RXM on the slot (one-shot per-slot gate) and enter&lt;br /&gt;
      NewReno-style careful recovery (see NewReno below in this&lt;br /&gt;
      section).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      The RACK reorder window R uses the RFC 8985 sec. 6.2 form&lt;br /&gt;
      R = MIN(reo_wnd_mult * min_RTT / 4, SRTT) with a&lt;br /&gt;
      MIN_REORDER_NS = 250 us floor.  Before the first RTT sample&lt;br /&gt;
      seeds min_rtt, R falls back to MIN(reo_wnd_mult * SRTT / 4,&lt;br /&gt;
      SRTT), still floored at MIN_REORDER_NS (consistent with the&lt;br /&gt;
      windowed-minimum fallback described in Section 12).  min_rtt&lt;br /&gt;
      is a windowed minimum over the last MIN_RTT_WIN_NS = 5 min of&lt;br /&gt;
      RTT samples (matches the Linux tcp_min_rtt_wlen default) so a&lt;br /&gt;
      route change to a longer path eventually re-anchors the&lt;br /&gt;
      reorder window without relying on reo_wnd_mult growth alone.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  SACK-driven retransmit&lt;br /&gt;
      For each gap below hi_sacked whose slot is (1) still owned,&lt;br /&gt;
      (2) not already SND_FAST_RXM, (3) not aged out past t_r, and&lt;br /&gt;
      (4) either outside the RACK window R OR with dup_thresh &amp;gt;=&lt;br /&gt;
      DUP_THRESH (same hybrid as fast-retransmit, see Section 6.2),&lt;br /&gt;
      re-emit.  Each SACK-driven retransmit re-arms a fresh rxm so&lt;br /&gt;
      a lost retransmit can still be recovered by its own RTO&lt;br /&gt;
      timer.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  NewReno&lt;br /&gt;
      On entry, recovery_high = snd_cr.seqno + RTT_QUARANTINE.&lt;br /&gt;
      Exit when ackno &amp;gt;= recovery_high or ackno == snd_cr.seqno&lt;br /&gt;
      (the latter means everything sent has been acknowledged).&lt;br /&gt;
      seqno_rotate also clears recovery.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds&lt;br /&gt;
(snd_cr.inact &amp;gt; rcv_cr.inact), so a receiver can detect &amp;quot;stale data&lt;br /&gt;
run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the&lt;br /&gt;
receiver-driven nudge that asks the sender to re-transmit the head&lt;br /&gt;
of the run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Send (frcti_nack_snd, called by frcti_rcv when rcv_inact_check&lt;br /&gt;
        returns FRCT_INACT_NEED_NACK)&lt;br /&gt;
      When an incoming DATA packet has no DRF and rcv-side activity&lt;br /&gt;
      is older than rcv_cr.inact, the receiver emits a bare packet&lt;br /&gt;
      with flags = FRCT_NACK and seqno = arrival_seqno - 1&lt;br /&gt;
      (informational only, not consulted by the receive handler).&lt;br /&gt;
      The cooldown in Section 3 rate-limits the burst.  Non-DATA&lt;br /&gt;
      non-DRF arrivals bypass rcv_inact_check entirely; non-DATA&lt;br /&gt;
      DRF still rebases via the DRF branch.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Receive (frcti_nack_rcv)&lt;br /&gt;
      Dispatched in the early-exit branch (Section 6.1), before&lt;br /&gt;
      rcv_inact_check.  The sender copies the head-of-line (HoL)&lt;br /&gt;
      rxm packet, marks the slot SND_RTX | SND_FAST_RXM (Karn-&lt;br /&gt;
      suppress next ACK, one-shot fast-rxm gate), sets rtt_lwe =&lt;br /&gt;
      snd_cr.lwe + 1, and re-emits via fast_rxm_send with FRCT_RXM&lt;br /&gt;
      and a refreshed ackno.  The original rxm_entry and its RTO&lt;br /&gt;
      timer are left armed - the NACK emit is additive to the&lt;br /&gt;
      normal retransmit machinery, not a replacement.  No-op if&lt;br /&gt;
      nothing is in flight, the HoL slot has aged past t_r, or&lt;br /&gt;
      the HoL rxm pointer has been cleared by SACK or RACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NACK serves two roles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. Lost first-of-run (DRF) packet recovery.  Required.  Until&lt;br /&gt;
     the DRF packet arrives, the receiver cannot rebase its&lt;br /&gt;
     window, so any subsequent in-flight packets look stale to&lt;br /&gt;
     the receiver.  The NACK fires the moment the second&lt;br /&gt;
     packet arrives at a stale receiver, telling the sender to&lt;br /&gt;
     re-emit the HoL (DRF) packet at NACK-cooldown latency rather&lt;br /&gt;
     than waiting for the initial RTO (which is the configured&lt;br /&gt;
     default until srtt is seeded by the first probe round-trip).&lt;br /&gt;
  2. General loss-recovery accelerator.  When loss is detected&lt;br /&gt;
     receiver-first, the NACK skips one RTO of latency relative to&lt;br /&gt;
     waiting for the sender&#039;s RTO to fire.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In both cases the existing rxm_entry and its RTO timer are left&lt;br /&gt;
armed, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is ackno = rcv_cr.lwe.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet (Section 1.3) whose payload lists&lt;br /&gt;
*present* blocks above lwe (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per Section 3 and suppressed when&lt;br /&gt;
neither lwe nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as block[0] of an&lt;br /&gt;
otherwise normal SACK frame (see Section 1.3 for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - DATA arrival with seqno &amp;lt; rcv_cr.lwe, both wire-dup (no RXM,&lt;br /&gt;
    is_dup_data path) and retransmit (RXM, post-FC branch)&lt;br /&gt;
    (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
  - rq_accept conflict, slot already occupied in [lwe, rwe)&lt;br /&gt;
    (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal ack_snd path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the TICTIME&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per Section 3&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
seqno, (2) rcv side is inactive (older than t_a), or (3) the&lt;br /&gt;
sender just sent within TICTIME.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises rwe in every FC field.  The sender treats&lt;br /&gt;
its snd_cr.rwe as the absolute right edge: when&lt;br /&gt;
snd_cr.seqno &amp;gt;= snd_cr.rwe the window is closed and flow_write&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence DELT_RDV); the receiver replies with&lt;br /&gt;
a bare FC packet (ackno = 0) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than MAX_RDV the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
rwe is clamped to lwe + RQ_SIZE on receipt and MUST NOT shrink:&lt;br /&gt;
a backward rwe is silently clamped to the current snd_cr.rwe;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes (Section 1.4) carry a 32-bit probe_id (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of RTTP_RING in-flight probes is&lt;br /&gt;
kept; an echo whose (id, nonce) doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to RTT_CLAMP_MUL * srtt&lt;br /&gt;
(compile-time RTT_CLAMP_MUL = 16) once srtt is seeded; the first&lt;br /&gt;
cold-probe sample feeds rtt_update raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Cold (no srtt yet): the receive path arms at most one probe&lt;br /&gt;
    per 100 ms via frcti_rcv_probe (PROBE_DUE_COLD); arming&lt;br /&gt;
    requires an incoming packet.  Active send-path arming bails&lt;br /&gt;
    while srtt == 0.&lt;br /&gt;
  - Warm (rtt_probe_arm, called from frcti_snd): outstanding&lt;br /&gt;
    data (snd_cr.seqno &amp;gt; snd_cr.lwe), AND at least 2 * srtt&lt;br /&gt;
    since t_rcv_rtt (last RTT receive of any kind), AND at&lt;br /&gt;
    least srtt since t_snd_probe (last probe emit).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric mdev estimator&lt;br /&gt;
(FRCT_LINUX_RTT_ESTIMATOR, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  srtt is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); mdev floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;lt;&amp;lt; MDEV_MUL))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the 2 * srtt floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per Section 3.&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (frcti_ack_rcv -&amp;gt; rtt_sample_eligible), beyond&lt;br /&gt;
the cum-ACK advance gate in frcti_ack_rcv (ackno &amp;gt; lwe and&lt;br /&gt;
ackno &amp;lt;= seqno), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry FRCT_RXM; HoL slot&#039;s SND_RTX bit clear; slot&#039;s rxm&lt;br /&gt;
pointer non-NULL (not SACK-consumed); lwe not below the rtt_lwe&lt;br /&gt;
fence; srtt already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds RACK.min_RTT (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than MIN_RTT_WIN_NS (5 min, matches Linux&lt;br /&gt;
tcp_min_rtt_wlen) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors min_RTT after at most one window).  Seeded from&lt;br /&gt;
rtt_hint at rtt_init; 0 acts as the unset sentinel and the base&lt;br /&gt;
in rack_reorder_window falls back from min_RTT to SRTT (so&lt;br /&gt;
R = mult * SRTT/4, capped at SRTT, floored at MIN_REORDER_NS)&lt;br /&gt;
until the first sample.  See Section 6.2.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When qs.timeout &amp;gt; 0 a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses rcv_cr.act for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    deadline = min(snd_act + qs.timeout/4,&lt;br /&gt;
                   rcv_act + qs.timeout)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to now + qs.timeout/4 if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (ka_snd) the peer-dead test&lt;br /&gt;
uses max(rcv_cr.act, t_ka_rcv) so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - If now - max(rcv_cr.act, t_ka_rcv) &amp;gt; qs.timeout, mark the flow&lt;br /&gt;
    ACL_FLOWPEER and notify the per-process flow-event set&lt;br /&gt;
    (proc.fqset) with FLOW_PEER.&lt;br /&gt;
  - Else if snd_idle &amp;gt; qs.timeout/4, emit a bare KA | ACK&lt;br /&gt;
    (ackno = rcv_cr.lwe) and re-arm.&lt;br /&gt;
  - Else just re-arm.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: rx_rb and tx_rb are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises ACL_FLOWDOWN on both (route is&lt;br /&gt;
broken); keepalive raises ACL_FLOWPEER on rx_rb only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps tx_rb usable) -&lt;br /&gt;
distinct ACLs.  qs.timeout == 0 disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On flow_dealloc, frcti_dealloc computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; flow_dealloc&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when rcv_cr.lwe != rcv_cr.seqno (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within t_a (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
FRCTFLINGER is honoured only when snd_cr.lwe &amp;lt; edge, where edge =&lt;br /&gt;
snd_fin_seqno after FIN has been sent in stream mode and&lt;br /&gt;
snd_cr.seqno otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in flow_dealloc&#039;s while (FRCTI_LINGERING) loop, not in&lt;br /&gt;
frcti_dealloc.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  flow_write pumps rx_rb on every call (via&lt;br /&gt;
flow_wait_window -&amp;gt; flow_drain_rx_nb) and additionally blocks on&lt;br /&gt;
rx_rb when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after t_mpl + a + r of silence), the DRF marker, and the&lt;br /&gt;
t_mpl / t_a / t_r timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified `flow_alloc(name, qos, ...)` primitive and its&lt;br /&gt;
multi-axis QoS-cube argument (Section 2.2) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| FRCP mechanism         | Heritage         | Reference / note       |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Random new seqno on    | TCP ISN          | RFC 6528 (Gont &amp;amp;       |&lt;br /&gt;
| seqno_rotate           |                  | Bellovin, 2012).       |&lt;br /&gt;
|                        |                  | QUIC PN-space reset    |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 12.3)   |&lt;br /&gt;
|                        |                  | is a structural        |&lt;br /&gt;
|                        |                  | analogue.              |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Cumulative ACK,        | TCP              | RFC 793 / RFC 9293     |&lt;br /&gt;
| left-window-edge       |                  |                        |&lt;br /&gt;
| advance                |                  |                        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Receive window with    | TCP              | RFC 793 sec. 3.7 /     |&lt;br /&gt;
| non-shrink rule        |                  | RFC 9293 sec. 3.8.6;   |&lt;br /&gt;
|                        |                  | RFC 1122 sec. 4.2.2.16 |&lt;br /&gt;
|                        |                  | for the explicit non-  |&lt;br /&gt;
|                        |                  | shrink prohibition     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Modular seqno          | TCP              | RFC 793 sec. 3.3 /     |&lt;br /&gt;
| arithmetic             |                  | RFC 9293 sec. 3.4      |&lt;br /&gt;
| (before/after helpers) |                  |                        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Selective ACK block    | TCP              | RFC 2018 (Mathis et    |&lt;br /&gt;
| list                   |                  | al., 1996).  Encoded   |&lt;br /&gt;
|                        |                  | as a typed FRCP packet |&lt;br /&gt;
|                        |                  | rather than a TCP      |&lt;br /&gt;
|                        |                  | option, so framing is  |&lt;br /&gt;
|                        |                  | closer to QUIC ACK     |&lt;br /&gt;
|                        |                  | frames.  D-SACK (RFC   |&lt;br /&gt;
|                        |                  | 2883) carried in-band  |&lt;br /&gt;
|                        |                  | as block[0]; see       |&lt;br /&gt;
|                        |                  | Section 1.3.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| NewReno-careful        | TCP              | RFC 6582 (Henderson    |&lt;br /&gt;
| recovery with          |                  | et al., 2012); QUIC    |&lt;br /&gt;
| recovery_high gate     |                  | builds on the same     |&lt;br /&gt;
|                        |                  | model in RFC 9002      |&lt;br /&gt;
|                        |                  | sec. 7.3.2.  Cwnd half |&lt;br /&gt;
|                        |                  | absent (CC in IPCP).   |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| RACK reordering        | TCP              | RFC 8985 (Cheng et     |&lt;br /&gt;
| window for fast        |                  | al., 2021).  FRCP      |&lt;br /&gt;
| retransmit             |                  | R = MIN(reo_wnd_mult * |&lt;br /&gt;
|                        |                  | min_RTT / 4, SRTT)     |&lt;br /&gt;
|                        |                  | with a MIN_REORDER_NS  |&lt;br /&gt;
|                        |                  | = 250 us floor against |&lt;br /&gt;
|                        |                  | srtt collapse; matches |&lt;br /&gt;
|                        |                  | RFC 8985 sec. 6.2 and  |&lt;br /&gt;
|                        |                  | Linux tcp_rack_reo_wnd.|&lt;br /&gt;
|                        |                  | DSACK-driven           |&lt;br /&gt;
|                        |                  | reo_wnd_mult (sec. 6.2 |&lt;br /&gt;
|                        |                  | step 4) is adopted;    |&lt;br /&gt;
|                        |                  | see Section 1.3 for    |&lt;br /&gt;
|                        |                  | the wire encoding.     |&lt;br /&gt;
|                        |                  | The hybrid RACK-or-    |&lt;br /&gt;
|                        |                  | DUP_THRESH trigger     |&lt;br /&gt;
|                        |                  | from RFC 8985 sec. 6.2 |&lt;br /&gt;
|                        |                  | step 4 is adopted      |&lt;br /&gt;
|                        |                  | (Section 8).  QUIC&#039;s   |&lt;br /&gt;
|                        |                  | analogue in RFC 9002   |&lt;br /&gt;
|                        |                  | sec. 6.1.2 uses        |&lt;br /&gt;
|                        |                  | max(srtt, latest_rtt)  |&lt;br /&gt;
|                        |                  | as the base.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Karn&#039;s algorithm:      | TCP              | Karn &amp;amp; Partridge,      |&lt;br /&gt;
| no RTT sample on       |                  | &amp;quot;Improving Round-Trip  |&lt;br /&gt;
| retransmits, RTO-      |                  | Time Estimates in      |&lt;br /&gt;
| collapse freeze        |                  | Reliable Transport     |&lt;br /&gt;
|                        |                  | Protocols&amp;quot;, SIGCOMM    |&lt;br /&gt;
|                        |                  | 1987; RFC 6298 sec. 3. |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| RTO formula            | TCP              | RFC 6298 (Paxson et    |&lt;br /&gt;
| RTO = max(RTO_MIN,     |                  | al., 2011).  RTO_MIN = |&lt;br /&gt;
| srtt + (mdev &amp;lt;&amp;lt;        |                  | 5 ms is below RFC 6298 |&lt;br /&gt;
| MDEV_MUL))             |                  | sec. 2.4&#039;s 1 s SHOULD- |&lt;br /&gt;
|                        |                  | floor - a recursive-   |&lt;br /&gt;
|                        |                  | layer choice.          |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Linux asymmetric mdev  | Linux kernel     | tcp_rtt_estimator() in |&lt;br /&gt;
| estimator (default)    |                  | net/ipv4/tcp_input.c;  |&lt;br /&gt;
|                        |                  | the if(delta&amp;lt;0) m&amp;gt;&amp;gt;=3  |&lt;br /&gt;
|                        |                  | dampening is a         |&lt;br /&gt;
|                        |                  | kernel divergence from |&lt;br /&gt;
|                        |                  | RFC 6298.  RFC 6298    |&lt;br /&gt;
|                        |                  | EWMA available behind  |&lt;br /&gt;
|                        |                  | a compile flag.        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Delayed ACK with rate  | TCP              | RFC 813 (Clark, 1982); |&lt;br /&gt;
| suppression            |                  | RFC 1122 sec. 4.2.3.2; |&lt;br /&gt;
|                        |                  | RFC 5681 sec. 4.2.     |&lt;br /&gt;
|                        |                  | Single-deadline        |&lt;br /&gt;
|                        |                  | coalescing rather than |&lt;br /&gt;
|                        |                  | &amp;quot;ack-every-other-      |&lt;br /&gt;
|                        |                  | segment&amp;quot;.              |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Zero-window-probe /    | TCP              | RFC 1122 sec.          |&lt;br /&gt;
| persist-timer          |                  | 4.2.2.17 / RFC 9293    |&lt;br /&gt;
| analogue (RDVS)        |                  | sec. 3.8.6.1.  RDVS    |&lt;br /&gt;
|                        |                  | solicits an FC reply,  |&lt;br /&gt;
|                        |                  | distinct from QUIC     |&lt;br /&gt;
|                        |                  | DATA_BLOCKED (RFC 9000 |&lt;br /&gt;
|                        |                  | sec. 19.12), which is  |&lt;br /&gt;
|                        |                  | one-way notification.  |&lt;br /&gt;
|                        |                  | MAX_RDV give-up        |&lt;br /&gt;
|                        |                  | departs from TCP.      |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Multiplexed control    | SCTP / QUIC      | SCTP chunk bundling    |&lt;br /&gt;
| on a single PCI        |                  | (RFC 9260 sec. 6.10);  |&lt;br /&gt;
|                        |                  | QUIC frame             |&lt;br /&gt;
|                        |                  | multiplexing (RFC 9000 |&lt;br /&gt;
|                        |                  | sec. 12.4).  Cleaner   |&lt;br /&gt;
|                        |                  | fit than TCP&#039;s         |&lt;br /&gt;
|                        |                  | separate-flag-bits     |&lt;br /&gt;
|                        |                  | design.                |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| ACK ranges as          | QUIC             | QUIC ACK frame (RFC    |&lt;br /&gt;
| multiple discontiguous |                  | 9000 sec. 19.3).  FRCP |&lt;br /&gt;
| acked blocks           |                  | SACK is conceptually   |&lt;br /&gt;
|                        |                  | QUIC-frame-shaped      |&lt;br /&gt;
|                        |                  | even though encoded    |&lt;br /&gt;
|                        |                  | as absolute            |&lt;br /&gt;
|                        |                  | [start,end] pairs.     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Nonce-authenticated    | QUIC             | PATH_CHALLENGE /       |&lt;br /&gt;
| active RTT / liveness  | PATH_CHALLENGE   | PATH_RESPONSE (RFC     |&lt;br /&gt;
| probing (RTTP)         |                  | 9000 sec. 8.2,         |&lt;br /&gt;
|                        |                  | sec. 19.17, sec.       |&lt;br /&gt;
|                        |                  | 19.18).  WebRTC ICE    |&lt;br /&gt;
|                        |                  | consent-freshness      |&lt;br /&gt;
|                        |                  | (RFC 7675) is the      |&lt;br /&gt;
|                        |                  | same pattern.  QUIC&#039;s  |&lt;br /&gt;
|                        |                  | nonce is 8 octets;     |&lt;br /&gt;
|                        |                  | FRCP chooses 16.       |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Probing distinct from  | QUIC             | KA timer answers       |&lt;br /&gt;
| keepalive              |                  | &amp;quot;peer alive?&amp;quot;, RTTP    |&lt;br /&gt;
|                        |                  | answers &amp;quot;path          |&lt;br /&gt;
|                        |                  | measurable?&amp;quot;, as in    |&lt;br /&gt;
|                        |                  | QUIC PING (RFC 9000    |&lt;br /&gt;
|                        |                  | sec. 19.2) vs          |&lt;br /&gt;
|                        |                  | PATH_CHALLENGE.        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Bare KA + ACK          | QUIC / SCTP      | QUIC PING (RFC 9000    |&lt;br /&gt;
| keepalive packets      |                  | sec. 19.2); SCTP       |&lt;br /&gt;
|                        |                  | HEARTBEAT /            |&lt;br /&gt;
|                        |                  | HEARTBEAT-ACK (RFC     |&lt;br /&gt;
|                        |                  | 9260 sec. 8.3).  SCTP  |&lt;br /&gt;
|                        |                  | HEARTBEAT also carries |&lt;br /&gt;
|                        |                  | an opaque echoed blob, |&lt;br /&gt;
|                        |                  | structurally similar   |&lt;br /&gt;
|                        |                  | to FRCP RTTP.          |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| (FFGM, LFGM)           | SCTP             | RFC 9260 sec. 3.3.1    |&lt;br /&gt;
| fragment-role bits     |                  | DATA chunk B/E bits    |&lt;br /&gt;
| (Section 7.2)          |                  | encode the same four   |&lt;br /&gt;
|                        |                  | states (B+E=SOLE,      |&lt;br /&gt;
|                        |                  | B-only=FIRST, neither  |&lt;br /&gt;
|                        |                  | =MID, E-only=LAST).    |&lt;br /&gt;
|                        |                  | Each fragment carries  |&lt;br /&gt;
|                        |                  | its own seqno/TSN and  |&lt;br /&gt;
|                        |                  | is independently       |&lt;br /&gt;
|                        |                  | retransmitted.         |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Stream byte-offset     | QUIC             | QUIC STREAM frame      |&lt;br /&gt;
| reassembly             |                  | (RFC 9000 sec. 19.8)   |&lt;br /&gt;
| (Sections 1.5, 16)     |                  | uses Offset + Length   |&lt;br /&gt;
|                        |                  | varints; FRCP uses     |&lt;br /&gt;
|                        |                  | fixed 32-bit start /   |&lt;br /&gt;
|                        |                  | end.  One stream per   |&lt;br /&gt;
|                        |                  | flow vs QUIC&#039;s many    |&lt;br /&gt;
|                        |                  | streams multiplexed.   |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| FIN end-of-stream      | TCP / QUIC       | TCP FIN flag (RFC 9293 |&lt;br /&gt;
| marker                 |                  | sec. 3.1) closes one   |&lt;br /&gt;
| (Sections 1.2, 16)     |                  | half of the byte       |&lt;br /&gt;
|                        |                  | stream; QUIC STREAM    |&lt;br /&gt;
|                        |                  | frame FIN bit (RFC     |&lt;br /&gt;
|                        |                  | 9000 sec. 19.8) does   |&lt;br /&gt;
|                        |                  | the same per stream    |&lt;br /&gt;
|                        |                  | with an immutable      |&lt;br /&gt;
|                        |                  | final-size invariance  |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 4.5:    |&lt;br /&gt;
|                        |                  | the final size is      |&lt;br /&gt;
|                        |                  | fixed once observed).  |&lt;br /&gt;
|                        |                  | FRCP&#039;s FIN consumes    |&lt;br /&gt;
|                        |                  | one packet seqno (not  |&lt;br /&gt;
|                        |                  | one byte of stream     |&lt;br /&gt;
|                        |                  | space) and is          |&lt;br /&gt;
|                        |                  | idempotent on the      |&lt;br /&gt;
|                        |                  | sender side.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Stream byte-credit     | QUIC             | MAX_STREAM_DATA (RFC   |&lt;br /&gt;
| flow control           |                  | 9000 sec. 4.1, sec.    |&lt;br /&gt;
| (Section 16)           |                  | 19.10).  FRCP projects |&lt;br /&gt;
|                        |                  | a per-flow byte budget |&lt;br /&gt;
|                        |                  | onto the seqno-space   |&lt;br /&gt;
|                        |                  | rwe.  Single stream    |&lt;br /&gt;
|                        |                  | per flow collapses     |&lt;br /&gt;
|                        |                  | QUIC&#039;s MAX_DATA /      |&lt;br /&gt;
|                        |                  | MAX_STREAM_            |&lt;br /&gt;
|                        |                  | DATA distinction.      |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Header protection      | QUIC             | QUIC RFC 9001 sec. 5.4 |&lt;br /&gt;
| (encrypted seqnos)     |                  | applies header         |&lt;br /&gt;
|                        |                  | protection on top of   |&lt;br /&gt;
|                        |                  | AEAD to mask the       |&lt;br /&gt;
|                        |                  | packet number.  FRCP&#039;s |&lt;br /&gt;
|                        |                  | per-flow AEAD wrap     |&lt;br /&gt;
|                        |                  | (Section 16) is wider: |&lt;br /&gt;
|                        |                  | it encrypts the entire |&lt;br /&gt;
|                        |                  | PCI including seqno    |&lt;br /&gt;
|                        |                  | because the IPCP       |&lt;br /&gt;
|                        |                  | below already routes,  |&lt;br /&gt;
|                        |                  | so no destination      |&lt;br /&gt;
|                        |                  | connection-ID needs to |&lt;br /&gt;
|                        |                  | stay in clear (cf.     |&lt;br /&gt;
|                        |                  | RFC 9000 sec. 5.2).    |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Two-bit fragment role  | SCTP             | The (FFGM, LFGM) pair  |&lt;br /&gt;
| polarity               |                  | follows SCTP B/E       |&lt;br /&gt;
|                        |                  | (begin = 1 / end = 1)  |&lt;br /&gt;
|                        |                  | rather than IPv4 MF    |&lt;br /&gt;
|                        |                  | (RFC 791 sec. 3.2),    |&lt;br /&gt;
|                        |                  | which has the inverse  |&lt;br /&gt;
|                        |                  | polarity (MF = 1 means |&lt;br /&gt;
|                        |                  | NOT last).             |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Orthogonal reliability | SCTP             | PR-SCTP (RFC 3758,     |&lt;br /&gt;
| / ordering axes        |                  | per-message partial    |&lt;br /&gt;
| (Section 2.2)          |                  | reliability) and SCTP  |&lt;br /&gt;
|                        |                  | DATA U-bit (RFC 9260   |&lt;br /&gt;
|                        |                  | sec. 3.3.1, per-       |&lt;br /&gt;
|                        |                  | message unordered)     |&lt;br /&gt;
|                        |                  | are the closest        |&lt;br /&gt;
|                        |                  | precedents for         |&lt;br /&gt;
|                        |                  | decoupling reliability |&lt;br /&gt;
|                        |                  | from ordering; FRCP    |&lt;br /&gt;
|                        |                  | sets them per-flow     |&lt;br /&gt;
|                        |                  | rather than per-       |&lt;br /&gt;
|                        |                  | message.               |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Orthogonal CRC         | UDP-Lite         | RFC 3828 (Larzon et    |&lt;br /&gt;
| (qs.ber == 0)          |                  | al., 2004) lets the    |&lt;br /&gt;
|                        |                  | sender pick a per-     |&lt;br /&gt;
|                        |                  | packet Checksum        |&lt;br /&gt;
|                        |                  | Coverage and the       |&lt;br /&gt;
|                        |                  | receiver enforce a     |&lt;br /&gt;
|                        |                  | locally configured     |&lt;br /&gt;
|                        |                  | minimum (no in-band    |&lt;br /&gt;
|                        |                  | negotiation; sec. 3.1, |&lt;br /&gt;
|                        |                  | sec. 3.3).  FRCP       |&lt;br /&gt;
|                        |                  | gates a full CRC       |&lt;br /&gt;
|                        |                  | trailer on qs.ber == 0 |&lt;br /&gt;
|                        |                  | at flow setup.         |&lt;br /&gt;
|                        |                  | Contrast TCP / SCTP    |&lt;br /&gt;
|                        |                  | (mandatory checksum)   |&lt;br /&gt;
|                        |                  | and QUIC (AEAD         |&lt;br /&gt;
|                        |                  | subsumes CRC).         |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Setup-time service     | DCCP / SCTP /    | DCCP Service Codes     |&lt;br /&gt;
| negotiation            | QUIC             | (RFC 4340 sec. 8.1.2,  |&lt;br /&gt;
|                        |                  | RFC 5595); SCTP INIT   |&lt;br /&gt;
|                        |                  | parameters (RFC 9260   |&lt;br /&gt;
|                        |                  | sec. 3.3.2); QUIC      |&lt;br /&gt;
|                        |                  | transport parameters   |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 7.4).   |&lt;br /&gt;
|                        |                  | All negotiate service  |&lt;br /&gt;
|                        |                  | properties at          |&lt;br /&gt;
|                        |                  | connection setup; only |&lt;br /&gt;
|                        |                  | RINA&#039;s QoS cube        |&lt;br /&gt;
|                        |                  | exposes them as an     |&lt;br /&gt;
|                        |                  | orthogonal vector.     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Pre-DRF NACK (Section 9): receiver-driven nudge exploiting&lt;br /&gt;
    snd_cr.inact &amp;gt; rcv_cr.inact.  Closest analogues are SCTP Gap Ack&lt;br /&gt;
    Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340&lt;br /&gt;
    sec. 11.4) - both let the receiver describe gaps to the sender,&lt;br /&gt;
    but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
  - MAX_RDV window-probe give-up: neither TCP (persist-timer&lt;br /&gt;
    probes until application or R2 abort, RFC 9293 sec. 3.8.6.1)&lt;br /&gt;
    nor QUIC has an explicit FC-give-up counter.  A recursive-&lt;br /&gt;
    network choice: outer layers can drop the flow.&lt;br /&gt;
  - Skip-past-gap reassembly (Section 7.2): SCTP fragments and&lt;br /&gt;
    reassembles every flow regardless of reliability/ordering,&lt;br /&gt;
    using its own per-stream reassembly queue; QUIC fragments via&lt;br /&gt;
    STREAM offsets.  FRCP fragments best-effort flows too, but&lt;br /&gt;
    the receiver drops the broken prefix the moment a later run-&lt;br /&gt;
    start (FIRST or SOLE role) is visible inside the RQ_SIZE-wide&lt;br /&gt;
    reorder ring - no IP-frag-style timeout, no SCTP-style&lt;br /&gt;
    explicit abort.  If no later run-start arrives within the&lt;br /&gt;
    ring, frag_run_inspect returns NOT_READY and the partial run&lt;br /&gt;
    keeps its slots; the next inspect retries.  The trade-off: a&lt;br /&gt;
    permanently-lost MID in a long isolated run holds slots until&lt;br /&gt;
    either a later FIRST/SOLE appears in the ring or the writer&lt;br /&gt;
    stops, at which point the slots are reclaimed on flow&lt;br /&gt;
    teardown.&lt;br /&gt;
  - Reassembly deferred to consume time (Section 7.2), message&lt;br /&gt;
    mode only (qos.service == SVC_MESSAGE): SCTP (RFC 9260&lt;br /&gt;
    sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all&lt;br /&gt;
    hold reassembly state at the receive boundary.  FRCP message-&lt;br /&gt;
    mode leaves fragments in the shared-memory ring until&lt;br /&gt;
    flow_read pulls and lands the SDU directly in the caller&#039;s&lt;br /&gt;
    buffer.  Stream mode (Section 16) uses the standard QUIC-&lt;br /&gt;
    style direct ring placement on receive and does not defer.&lt;br /&gt;
    The optimisation is enabled by the Shared-Memory Subsystem&lt;br /&gt;
    (SSM) packet-buffer ring (see struct ssm_pk_buff at&lt;br /&gt;
    Section 1.1); the analogue is OS-level scatter-gather I/O&lt;br /&gt;
    (recvmsg+iovec), not a transport-layer prior art.&lt;br /&gt;
  - TLP-equivalent tail-loss recovery (RFC 8985 sec. 7;&lt;br /&gt;
    RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss&lt;br /&gt;
    Probe packet, but the same goal is met implicitly by RACK&lt;br /&gt;
    loss detection (Section 8) firing on a non-advancing&lt;br /&gt;
    cumulative ACK once the head-of-line slot ages past the RACK&lt;br /&gt;
    reorder window R = MIN(reo_wnd_mult * min_RTT / 4, SRTT) -&lt;br /&gt;
    well below RTO = max(2 * SRTT, SRTT + (mdev &amp;lt;&amp;lt; MDEV_MUL)).&lt;br /&gt;
    A receiver-driven nudge is also available via the pre-DRF&lt;br /&gt;
    NACK (Section 9).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Slow start, congestion window (cwnd), Additive Increase /&lt;br /&gt;
    Multiplicative Decrease (AIMD), NewReno cwnd inflation.&lt;br /&gt;
    Congestion control lives in the IPCP CA policies and is&lt;br /&gt;
    driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
  - Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC&lt;br /&gt;
    1122 sec. 4.2.3.4).  (Deferred work, not adopted in the&lt;br /&gt;
    current spec.)&lt;br /&gt;
  - TCP Timestamps (RFC 7323) / Protection Against Wrapped&lt;br /&gt;
    Sequences (PAWS) - RTT measurement uses RTTP,&lt;br /&gt;
    not per-segment timestamps.  A peer-supplied timestamp echoed&lt;br /&gt;
    on every ACK lets a malicious peer drive the srtt estimate&lt;br /&gt;
    arbitrarily low, collapsing the RTO and triggering a self-&lt;br /&gt;
    inflicted retransmit storm.  RTTP confines RTT measurement to&lt;br /&gt;
    nonce-authenticated probe round-trips, where a forged echo is&lt;br /&gt;
    rejected before it can reach the estimator.&lt;br /&gt;
  - ECN (Explicit Congestion Notification) response inside FRCP&lt;br /&gt;
    (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
  - IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200&lt;br /&gt;
    sec. 4.5).  Message-mode FRCP relies on the FRCT rq[] reorder&lt;br /&gt;
    ring keyed by seqno (shared by FRTX and best-effort flows) to&lt;br /&gt;
    put fragments back in order; no separate offset field is&lt;br /&gt;
    needed and no IP-style hole-list reassembly buffer is kept.&lt;br /&gt;
    Stream-mode FRCP does carry [start, end) byte offsets&lt;br /&gt;
    (Section 1.5) for direct ring placement on receive.&lt;br /&gt;
  - QUIC STREAM offset+length framing on *every* flow (RFC 9000&lt;br /&gt;
    sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-&lt;br /&gt;
    bit encoding (FFGM/LFGM) and skips the offsets; stream-mode&lt;br /&gt;
    FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with qos.service == SVC_STREAM both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections 6-8.&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension) octets (Sections 1.1&lt;br /&gt;
and 1.5).  Each chunk is one DATA packet with its own seqno and a&lt;br /&gt;
[start, end) byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode FFGM and LFGM are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the [start, end)&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has FIN&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in Section 1.2&lt;br /&gt;
(WR-half close, flow_dealloc, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
[start, end) MUST equal [final-byte, final-byte) (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an snd_fin_sent guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width ring_sz (octets) at the position&lt;br /&gt;
indicated by start, with a two-segment memcpy across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery (Section 6.2) augmented with the packet&#039;s start, end, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s [start, end) front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances lwe and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy `start == the last-delivered slot&#039;s end`; a slot whose&lt;br /&gt;
start does not equal that end is silently dropped at delivery time&lt;br /&gt;
(the seqno is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s end; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding seqno occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
flow_read returns up to count octets from the contiguous prefix&lt;br /&gt;
[next, high-water), where next is the byte the application has&lt;br /&gt;
already consumed up to and high-water is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (next == EOS byte position), flow_read returns&lt;br /&gt;
0 (EOF) - the same shape POSIX read(2) uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-seqno received-bitmap.  Let per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension), the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry (Section 16.1).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(ring_sz) cannot be overrun: the seqno-space rwe is at most&lt;br /&gt;
`rcv_cr.lwe + ring_sz / per_pkt`.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(MAX_STREAM_DATA, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
seqno space.  With one stream per flow there is no MAX_DATA /&lt;br /&gt;
MAX_STREAM_DATA distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time rwe bump with the global non-shrink rule from&lt;br /&gt;
Section 11.&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (start == prior&lt;br /&gt;
end on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when ber == 0 - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
(Section 1.1).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see Section 1.1).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
  - Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
  - Comparable to IPsec ESP transport mode (RFC 4303), which&lt;br /&gt;
    similarly authenticates and encrypts the upper-layer header&lt;br /&gt;
    plus payload, and to QUIC packet protection (RFC 9001 sec. 5),&lt;br /&gt;
    with the difference that QUIC must leave the destination&lt;br /&gt;
    connection ID in the clear for routing whereas FRCP relies on&lt;br /&gt;
    the IPCP below for delivery and can therefore encrypt its&lt;br /&gt;
    entire PCI.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keying granularity.  FRCP runs key exchange (kex) per flow, so&lt;br /&gt;
each flow_alloc yields independent symmetric keys.  This is&lt;br /&gt;
finer-grained than QUIC (per-connection, RFC 9001, where one&lt;br /&gt;
handshake covers all multiplexed streams) and finer-grained than&lt;br /&gt;
typical IPsec deployment (per-host-pair Security Associations,&lt;br /&gt;
SAs).  Forward secrecy follows from the kex when an ephemeral&lt;br /&gt;
Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH +&lt;br /&gt;
post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection.  The AEAD layer itself does NOT carry an&lt;br /&gt;
explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec.&lt;br /&gt;
3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the&lt;br /&gt;
seqno-space duplicate-suppression in Section 6.2 rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates&lt;br /&gt;
the seqno and a replay re-presents an old seqno that is then&lt;br /&gt;
discarded either as a duplicate (still inside the receive window)&lt;br /&gt;
or as outside the receive window, depending on how far lwe has&lt;br /&gt;
advanced since the original packet was delivered.  RAW&lt;br /&gt;
(qos.service == SVC_RAW) flows have no FRCP layer and therefore&lt;br /&gt;
no replay protection at the AEAD layer either; deployments that&lt;br /&gt;
need replay rejection on RAW flows MUST provide it at a higher&lt;br /&gt;
layer.&lt;br /&gt;
&lt;br /&gt;
Layering.  The AEAD wrap sits below FRCP on the data path, so&lt;br /&gt;
RAW best-effort flows (qos.service == SVC_RAW, the UDP-equivalent&lt;br /&gt;
service of Section 2.2) inherit the same per-flow integrity +&lt;br /&gt;
confidentiality scope as FRCP-engaged flows - whatever the IPCP&lt;br /&gt;
and FRCP (if any) put on the wire is what the AEAD authenticates.&lt;br /&gt;
No DTLS-equivalent layering is required for confidentiality and&lt;br /&gt;
integrity; replay protection above AEAD is a separate concern as&lt;br /&gt;
noted above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 791]   J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791,&lt;br /&gt;
              September 1981.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 793]   J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7,&lt;br /&gt;
              RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 813]   D. D. Clark, &amp;quot;Window and Acknowledgement Strategy&lt;br /&gt;
              in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 896]   J. Nagle, &amp;quot;Congestion Control in IP/TCP&lt;br /&gt;
              Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 1122]  R. Braden (ed.), &amp;quot;Requirements for Internet Hosts&lt;br /&gt;
              -- Communication Layers&amp;quot;, STD 3, RFC 1122,&lt;br /&gt;
              October 1989.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2018]  M. Mathis, J. Mahdavi, S. Floyd, A. Romanow,&lt;br /&gt;
              &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018,&lt;br /&gt;
              October 1996.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2119]  S. Bradner, &amp;quot;Key words for use in RFCs to Indicate&lt;br /&gt;
              Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2883]  S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky,&lt;br /&gt;
              &amp;quot;An Extension to the Selective Acknowledgement&lt;br /&gt;
              (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 3758]  R. Stewart, M. Ramalho, Q. Xie, M. Tuexen,&lt;br /&gt;
              P. Conrad, &amp;quot;Stream Control Transmission Protocol&lt;br /&gt;
              (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758,&lt;br /&gt;
              May 2004.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 3828]  L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson&lt;br /&gt;
              (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User&lt;br /&gt;
              Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828,&lt;br /&gt;
              July 2004.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 4303]  S. Kent, &amp;quot;IP Encapsulating Security Payload&lt;br /&gt;
              (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 4340]  E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram&lt;br /&gt;
              Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340,&lt;br /&gt;
              March 2006.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5288]  J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois&lt;br /&gt;
              Counter Mode (GCM) Cipher Suites for TLS&amp;quot;,&lt;br /&gt;
              RFC 5288, August 2008.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5595]  G. Fairhurst, &amp;quot;The Datagram Congestion Control&lt;br /&gt;
              Protocol (DCCP) Service Codes&amp;quot;, RFC 5595,&lt;br /&gt;
              September 2009.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5681]  M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion&lt;br /&gt;
              Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5925]  J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP&lt;br /&gt;
              Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5961]  A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving&lt;br /&gt;
              TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;,&lt;br /&gt;
              RFC 5961, August 2010.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6298]  V. Paxson, M. Allman, J. Chu, M. Sargent,&lt;br /&gt;
              &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298,&lt;br /&gt;
              June 2011.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6528]  F. Gont, S. Bellovin, &amp;quot;Defending against Sequence&lt;br /&gt;
              Number Attacks&amp;quot;, RFC 6528, February 2012.&lt;br /&gt;
              Obsoletes RFC 1948.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6582]  T. Henderson, S. Floyd, A. Gurtov, Y. Nishida,&lt;br /&gt;
              &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery&lt;br /&gt;
              Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 7323]  D. Borman, B. Braden, V. Jacobson,&lt;br /&gt;
              R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High&lt;br /&gt;
              Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 7675]  M. Perumal, D. Wing, R. Ravindranath, T. Reddy,&lt;br /&gt;
              M. Thomson, &amp;quot;Session Traversal Utilities for NAT&lt;br /&gt;
              (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675,&lt;br /&gt;
              October 2015.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8174]  B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in&lt;br /&gt;
              RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8200]  S. Deering, R. Hinden, &amp;quot;Internet Protocol,&lt;br /&gt;
              Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200,&lt;br /&gt;
              July 2017.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8439]  Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF&lt;br /&gt;
              Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8446]  E. Rescorla, &amp;quot;The Transport Layer Security (TLS)&lt;br /&gt;
              Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8985]  Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha,&lt;br /&gt;
              &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;,&lt;br /&gt;
              RFC 8985, February 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9000]  J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A&lt;br /&gt;
              UDP-Based Multiplexed and Secure Transport&amp;quot;,&lt;br /&gt;
              RFC 9000, May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9001]  M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to&lt;br /&gt;
              Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9002]  J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss&lt;br /&gt;
              Detection and Congestion Control&amp;quot;, RFC 9002,&lt;br /&gt;
              May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9147]  E. Rescorla, H. Tschofenig, N. Modadugu,&lt;br /&gt;
              &amp;quot;The Datagram Transport Layer Security (DTLS)&lt;br /&gt;
              Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9260]  R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control&lt;br /&gt;
              Transmission Protocol&amp;quot;, RFC 9260, June 2022.&lt;br /&gt;
              Obsoletes RFC 4960.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9293]  W. Eddy (ed.), &amp;quot;Transmission Control Protocol&lt;br /&gt;
              (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes&lt;br /&gt;
              RFC 793 and several follow-ons; updates RFC 1122&lt;br /&gt;
              and others.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - J. Day, &amp;quot;Patterns in Network Architecture: A Return to&lt;br /&gt;
    Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative&lt;br /&gt;
    to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates&lt;br /&gt;
    in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport&lt;br /&gt;
    Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5,&lt;br /&gt;
    1981.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - tcp_rtt_estimator() in net/ipv4/tcp_input.c of the Linux&lt;br /&gt;
    kernel, defining the asymmetric mdev variance update used as&lt;br /&gt;
    FRCP&#039;s default RTT estimator (Section 12).  Line-stable&lt;br /&gt;
    browseable copy at&lt;br /&gt;
    https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1912</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1912"/>
		<updated>2026-05-17T13:51:01Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Table of Contents */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= FRCP - Flow and Retransmission Control Protocol =&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in src/lib/frct.c.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the FRCT_ prefix&lt;br /&gt;
(FRCT_DATA, FRCT_RXM, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in BCP 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  u32, u8       Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
  ns            Nanoseconds.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    before(a, b)  ==  (int32_t)(a - b) &amp;lt; 0&lt;br /&gt;
    after(a, b)   ==  before(b, a)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for ackno / seqno ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    SRTT          Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
    mdev          Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
    EWMA          Exponentially Weighted Moving Average.&lt;br /&gt;
    RTO           Retransmission Timeout, max(RTO_MIN,&lt;br /&gt;
                  srtt + (mdev &amp;lt;&amp;lt; MDEV_MUL)).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols t_a (a-timer, ACK delay) and t_r (r-timer,&lt;br /&gt;
retransmission window) are defined in Section 8; t_mpl (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in Section 2.1 (the inact field)&lt;br /&gt;
with heritage in Section 15.&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except hcs&lt;br /&gt;
are in network byte order; hcs is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place pci-&amp;gt;hcs read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
Section 1.5); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  flags   - feature/type bitmap (see 1.2).&lt;br /&gt;
  hcs     - CRC-16-CCITT-FALSE Header Check Sequence (HCS) over&lt;br /&gt;
            flags + window + seqno + ackno (+ stream extension when&lt;br /&gt;
            present); the two octets of the hcs field itself are&lt;br /&gt;
            omitted from the CRC input.  Verified on receive before&lt;br /&gt;
            any flag-driven dispatch.&lt;br /&gt;
  window  - receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
  seqno   - per-flow sequence number.&lt;br /&gt;
  ackno   - cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see Section 2.2).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    [   PCI + body          ]    -- the FRCP packet&lt;br /&gt;
    [   PCI + body + CRC-32 ]    -- CRC-32 covers the body only (PCI&lt;br /&gt;
                                    is in HCS); appended iff qs.ber&lt;br /&gt;
                                    == 0 on DATA, or on every SACK&lt;br /&gt;
                                    packet&lt;br /&gt;
    [ AEAD-wrap of above    ]    -- iff Authenticated Encryption&lt;br /&gt;
                                    with Associated Data (AEAD) is&lt;br /&gt;
                                    enabled&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - HCS in the PCI covers the header fields on every packet and is&lt;br /&gt;
    verified before any flag-driven dispatch.&lt;br /&gt;
  - The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial&lt;br /&gt;
    0xEDB88320, init 0xFFFFFFFF, xor-out 0xFFFFFFFF) covers the&lt;br /&gt;
    body on DATA when qs.ber == 0 and on every SACK packet; the&lt;br /&gt;
    trailer is written as a raw uint32_t (the same convention as&lt;br /&gt;
    hcs: opaque on the wire as long as both peers run compatible&lt;br /&gt;
    builds).  The PCI is not under the CRC (Cyclic Redundancy&lt;br /&gt;
    Check) because the HCS already protects it.  It is&lt;br /&gt;
    appended before AEAD encryption and therefore rides inside the&lt;br /&gt;
    AEAD wrap when both are active; the AEAD tag (~2^-128 forgery&lt;br /&gt;
    probability) dominates the CRC (~2^-32) for integrity in that&lt;br /&gt;
    mode but the CRC trailer is currently retained.&lt;br /&gt;
  - When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP&lt;br /&gt;
    packet is wrapped with AEAD inside the shared-memory packet&lt;br /&gt;
    buffer (spb, struct ssm_pk_buff); the packet grows by the AEAD&lt;br /&gt;
    overhead, namely a leading nonce / Initialization Vector (IV)&lt;br /&gt;
    of headsz bytes (crypt_get_ivsz) and a trailing authentication&lt;br /&gt;
    tag of tailsz bytes (crypt_get_tagsz).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and&lt;br /&gt;
are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per Section 1.1; bit 0 is the MSB of the&lt;br /&gt;
16-bit flags field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
    | Bit  | Mask   | Name   | Meaning                                |&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
    |   0  | 0x8000 | DATA   | Carries caller payload                 |&lt;br /&gt;
    |   1  | 0x4000 | DRF    | Data Run Flag: start of a fresh run    |&lt;br /&gt;
    |   2  | 0x2000 | ACK    | Acknowledgement: ackno field valid     |&lt;br /&gt;
    |   3  | 0x1000 | NACK   | Negative ACK; seqno = arrival_seqno-1  |&lt;br /&gt;
    |   4  | 0x0800 | FC     | Flow Control: window field valid (rwe) |&lt;br /&gt;
    |   5  | 0x0400 | RDVS   | Rendezvous probe (window-closed)       |&lt;br /&gt;
    |   6  | 0x0200 | FFGM   | First Fragment (role bit 0; see below) |&lt;br /&gt;
    |   7  | 0x0100 | LFGM   | Last Fragment (role bit 1; see below)  |&lt;br /&gt;
    |   8  | 0x0080 | RXM    | Retransmission                         |&lt;br /&gt;
    |   9  | 0x0040 | SACK   | Selective ACK block list in payload    |&lt;br /&gt;
    |  10  | 0x0020 | RTTP   | RTT Probe / echo (payload follows)     |&lt;br /&gt;
    |  11  | 0x0010 | KA     | Keepalive                              |&lt;br /&gt;
    |  12  | 0x0008 | FIN    | End-of-stream marker (stream mode)     |&lt;br /&gt;
    | 13-15|   --   |  --    | Reserved (MUST be zero)                |&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The (FFGM, LFGM) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
    | FFGM LFGM | Role                                            |&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
    |   1   1   | Sole / un-fragmented SDU (begin AND end)        |&lt;br /&gt;
    |   1   0   | First fragment of a multi-fragment SDU          |&lt;br /&gt;
    |   0   0   | Middle fragment                                 |&lt;br /&gt;
    |   0   1   | Last fragment                                   |&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own seqno;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see Section 2.2)&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (qos.service == SVC_STREAM, see Section 16) there are&lt;br /&gt;
no SDU boundaries to encode, so FFGM and LFGM are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (FIN,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(fccntl to FLOWFRDONLY), during linger drain, and at flow_dealloc;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches byte_fin at the FIN&#039;s&lt;br /&gt;
start offset; flow_read returns 0 (end-of-file, EOF) once buffered&lt;br /&gt;
bytes have been drained up to byte_fin.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension (Section 1.5).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the FRCT_ACK | FRCT_FC | FRCT_SACK flag bits set&lt;br /&gt;
(bit numbering per Section 1.1).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then n_blocks pairs of&lt;br /&gt;
32-bit start/end seqnos describing *present* (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
n_blocks &amp;lt;= SACK_MAX_BLOCKS (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by (frag_mtu - PCI - 4) / 8 blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI ackno field (after(start[i], ackno)).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
before() / after() comparators defined in the Notation block.&lt;br /&gt;
Block[0] carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  case 1 (RFC 2883 sec. 4.1.1, full duplicate):&lt;br /&gt;
      before(blocks[0].start, ackno) and ackno - blocks[0].start is&lt;br /&gt;
      within MAX_DSACK_LAG (== RQ_SIZE).  A single duplicate seqno&lt;br /&gt;
      observed below the cumulative ACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  case 2 (RFC 2883 sec. 4.1.2, partial duplicate):&lt;br /&gt;
      blocks[0] is a sub-range of some blocks[i&amp;gt;0] (not exactly&lt;br /&gt;
      equal).  Reports a duplicate of an in-window seqno that the&lt;br /&gt;
      same packet&#039;s remaining SACK blocks already describe as&lt;br /&gt;
      received.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Senders that do not implement D-SACK process block[0] through the&lt;br /&gt;
normal SACK-mark loop and the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (start &amp;lt; snd_cr.lwe clamps to snd_cr.lwe, the inner&lt;br /&gt;
loop then skips k == snd_cr.lwe) and case-2 idempotent (same slots&lt;br /&gt;
NULL&#039;d twice).  D-SACK-aware senders feed the report into the RACK&lt;br /&gt;
reo_wnd_mult scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see Section 8); only non-D-SACK blocks&lt;br /&gt;
count as gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the FRCT_RTTP flag&lt;br /&gt;
set (bit numbering per Section 1.1).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  probe_id - sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
  echo_id  - peer&#039;s probe_id, 0 on outbound probe.&lt;br /&gt;
  nonce    - random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (qos.service == SVC_STREAM) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per Section 1.1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  start - octet offset of the first payload byte in the stream.&lt;br /&gt;
  end   - octet offset one past the last payload byte;&lt;br /&gt;
          end - start equals the on-wire payload length.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat start/end as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with start not equal to the prior packet&#039;s end the&lt;br /&gt;
slot is silently dropped at delivery time (Section 16) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet seqno (this PCI&#039;s seqno field) and a&lt;br /&gt;
separate stream byte position (start/end).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet FRCT_RXM,&lt;br /&gt;
per-slot SND_RTX flags, and a sample-fence rtt_lwe (see Section 2.1&lt;br /&gt;
and Section 12).  FRCP&#039;s fixed-32-bit start/end wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular before()&lt;br /&gt;
/ after() comparators (Section 1.3) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in before()).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps ring_sz at 128 MiB (FRCT_STREAM_RING_SZ_MAX),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform size_t and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    lwe    : u32  snd: oldest unacked seqno (cumulative ACK&lt;br /&gt;
                  boundary as seen by sender);&lt;br /&gt;
                  rcv: next in-order seqno expected&lt;br /&gt;
    rwe    : u32  snd: peer-advertised right window edge;&lt;br /&gt;
                  rcv: locally-advertised right window edge&lt;br /&gt;
    cflags : u8   per-direction feature flags: retransmission&lt;br /&gt;
                  (FRCTFRTX), receiver flow control&lt;br /&gt;
                  (FRCTFRESCNTL), linger-on-close (FRCTFLINGER);&lt;br /&gt;
                  see &amp;lt;ouroboros/fccntl.h&amp;gt;&lt;br /&gt;
    seqno  : u32  snd: next seqno to send;&lt;br /&gt;
                  rcv: force-ACK trigger - set on a stale or dup&lt;br /&gt;
                  DATA so the next ack_snd emits a fresh&lt;br /&gt;
                  cumulative ACK&lt;br /&gt;
    ackno  : u32  snd: outbound ACK-packet seqno counter,&lt;br /&gt;
                  incremented for every ACK-bearing packet (bare&lt;br /&gt;
                  ACK, delayed ACK, SACK); used by wire-dup ACK&lt;br /&gt;
                  detection;&lt;br /&gt;
                  rcv: incoming-ACK dedup tracker&lt;br /&gt;
    act    : ns   last activity (used by inactivity / DRF)&lt;br /&gt;
    inact  : ns   inactivity threshold; sender = 3*mpl + a + r + 1s,&lt;br /&gt;
                  receiver = 2*mpl + a + r + 1s.  mpl is the&lt;br /&gt;
                  Maximum Packet Lifetime (delta-t terminology;&lt;br /&gt;
                  see Section 15); a and r are the FRCT a-timer&lt;br /&gt;
                  and r-timer bounds (see Section 8).  The&lt;br /&gt;
                  asymmetry is load-bearing for pre-DRF NACK&lt;br /&gt;
                  (Section 9).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring snd_slots[RQ_SIZE] keyed by&lt;br /&gt;
(seqno mod RQ_SIZE).  Each slot tracks its retransmit entry (rxm),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: SND_RTX (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and SND_FAST_RXM (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring rcv_slots[RQ_SIZE]&lt;br /&gt;
(referred to as rq[] in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant rwe - lwe &amp;lt;= RQ_SIZE holds: on each consume&lt;br /&gt;
the receiver advances rwe by the consumed count, capping the&lt;br /&gt;
receive window at RQ_SIZE seqno slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable rtt_lwe is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
seqno_rotate (Section 4) to mark the seqno range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same flow_alloc(name, qos, ...) primitive; the qosspec_t passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (SOCK_STREAM / SOCK_DGRAM).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  service   0 = unordered (no FRCP engagement: raw datagrams,&lt;br /&gt;
              no PCI on the wire, UDP-equivalent at this layer)&lt;br /&gt;
            1 = message-ordered (FRCP engaged; SDU boundaries&lt;br /&gt;
              preserved across fragmentation)&lt;br /&gt;
            2 = stream (byte-oriented, no SDU boundaries; FRTX&lt;br /&gt;
              required)&lt;br /&gt;
  loss      0 = lossless service requested: FRTX retransmit&lt;br /&gt;
              machinery engages (Section 8); MUST be 0 for&lt;br /&gt;
              service=2.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
  ber       Bit Error Rate tolerance.&lt;br /&gt;
            0 = error-free service requested: a CRC trailer is&lt;br /&gt;
              appended after the body of DATA packets and verified&lt;br /&gt;
              on receive (added / checked outside the FRCP PCI;&lt;br /&gt;
              see Section 1.1).  Non-zero = peer accepts errors;&lt;br /&gt;
              trailer omitted.  SACK control packets carry a&lt;br /&gt;
              CRC32 trailer regardless of ber; the ber gate&lt;br /&gt;
              applies to DATA only.&lt;br /&gt;
  timeout   Peer-timeout (ms); 0 disables the keepalive timer.&lt;br /&gt;
              Independent of FRCP engagement.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the spb by headsz + tailsz&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see Section 1.1).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by include/ouroboros/qos.h:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
  | Cube            | service | loss | ber | Engaged               |&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
  | qos_raw         |    0    |   1  |   1 | Raw passthrough       |&lt;br /&gt;
  | qos_raw_safe    |    0    |   1  |   0 | Raw + CRC trailer     |&lt;br /&gt;
  | qos_rt          |    1    |   1  |   1 | FRCP, no FRTX, no CRC |&lt;br /&gt;
  | qos_rt_safe     |    1    |   1  |   0 | FRCP, no FRTX, CRC    |&lt;br /&gt;
  | qos_msg         |    1    |   0  |   0 | FRCP + FRTX           |&lt;br /&gt;
  | qos_stream      |    2    |   0  |   0 | FRCP + FRTX, stream   |&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - service == SVC_STREAM (2) requires loss == 0; flow_alloc /&lt;br /&gt;
    flow_accept reject the pair otherwise with -EINVAL.&lt;br /&gt;
  - FRTX requires FRCP engagement (service != SVC_RAW); requesting&lt;br /&gt;
    loss = 0 with service = SVC_RAW is structurally a no-op&lt;br /&gt;
    because no frcti is created.&lt;br /&gt;
  - The QOS_DISABLE_CRC build flag globally forces ber = 1.&lt;br /&gt;
    Note: this flag defaults to ON, so default builds ship with&lt;br /&gt;
    CRC disabled until QOS_DISABLE_CRC is set to OFF.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force ber = 0 when service != SVC_RAW.&lt;br /&gt;
qos_rt has service = SVC_MESSAGE with ber = 1, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS (Section 1.1)&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (service = SVC_MESSAGE, loss &amp;gt; 0) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly (Section 7.2) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
    | Parameter          | Value                  | Role              |&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
    | RQ_SIZE            | compile-time, power of | Slot ring / rcv   |&lt;br /&gt;
    |                    |  2 (default 128)       | window width      |&lt;br /&gt;
    | START_WINDOW       | compile-time, power of | Initial rwe-lwe   |&lt;br /&gt;
    |                    |  2 (default 128)       | after rotate      |&lt;br /&gt;
    | RTO_MIN            | MAX(250 us build-tun-  | RTO floor; also   |&lt;br /&gt;
    |                    |  able, 1&amp;lt;&amp;lt;RXMQ_RES);   | floored at the    |&lt;br /&gt;
    |                    |  per-flow via fccntl   | retransmit-wheel  |&lt;br /&gt;
    |                    |  (FRCTSRTOMIN).        | resolution        |&lt;br /&gt;
    |                    |  Default ~1 ms with    | (~1 ms by         |&lt;br /&gt;
    |                    |  RXMQ_RES=20.          | default).         |&lt;br /&gt;
    | MAX_RTO_MUL        | 20                     | Backoff shift cap |&lt;br /&gt;
    | RACK window R      | MIN(reo_wnd_mult       | Reorder window;   |&lt;br /&gt;
    |                    |  * min_RTT/4, SRTT)    | per RFC 8985      |&lt;br /&gt;
    |                    |  with MIN_REORDER_NS   | sec. 6.2;         |&lt;br /&gt;
    |                    |  = 250 us floor;       | reo_wnd_mult per  |&lt;br /&gt;
    |                    |  reo_wnd_mult scales   | sec. 6.2 step 4   |&lt;br /&gt;
    |                    |  on D-SACK, cap 20     |                   |&lt;br /&gt;
    | MIN_RTT_WIN_NS     | 300 s (5 min, Linux    | min_RTT windowed  |&lt;br /&gt;
    |                    |  tcp_min_rtt_wlen)     | re-anchor         |&lt;br /&gt;
    | REO_WND_MULT_MAX   | 20 (RFC 8985 sec.      | reo_wnd_mult cap  |&lt;br /&gt;
    |                    |  6.2 step 4)           |                   |&lt;br /&gt;
    | REO_DECAY_PKTS     | 16 (RFC 8985 sec.      | Fresh-ACK&#039;d seq   |&lt;br /&gt;
    |                    |  6.2 step 4 /          | count per halving |&lt;br /&gt;
    |                    |  RACK.reo_wnd_persist) |                   |&lt;br /&gt;
    | MAX_DSACK_LAG      | RQ_SIZE                | D-SACK sanity cap |&lt;br /&gt;
    | RTT_QUARANTINE     | 32 (seqno steps)       | NewReno gate pad  |&lt;br /&gt;
    | SACK rate-limit    | SACK_MIN_GAP_NS        | Min SACK gap      |&lt;br /&gt;
    |                    |  (250 us, fixed)       |                   |&lt;br /&gt;
    | SACK_MAX_BLOCKS    | 2048 (wire cap; per-   | Per-SACK block    |&lt;br /&gt;
    |                    |  flow capped at        | cap               |&lt;br /&gt;
    |                    |  (frag_mtu-PCI-4)/8)   |                   |&lt;br /&gt;
    | SACK_RXM_MAX       | 32                     | Per-pass staged   |&lt;br /&gt;
    |                    |                        | retransmit cap    |&lt;br /&gt;
    | DUP_THRESH         | 3 (RFC 8985 default)   | Hybrid fast-rxm   |&lt;br /&gt;
    |                    |                        | trigger (Sec. 8)  |&lt;br /&gt;
    | MDEV_MUL           | 2 (build-tunable via   | mdev shift in     |&lt;br /&gt;
    |                    |  FRCT_RTO_MDEV_-       | RTO = srtt +      |&lt;br /&gt;
    |                    |  MULTIPLIER)           | (mdev &amp;lt;&amp;lt; MDEV_MUL)|&lt;br /&gt;
    | RTTP nonce         | 16 octets              | Echoed verbatim   |&lt;br /&gt;
    | RTTP_RING          | 8                      | In-flight probes  |&lt;br /&gt;
    | RTT clamp          | 16 * srtt              | Probe-sample      |&lt;br /&gt;
    |                    |                        | upper bound       |&lt;br /&gt;
    |                    |                        | (ACK-derived RTT  |&lt;br /&gt;
    |                    |                        | samples gated by  |&lt;br /&gt;
    |                    |                        | Karn / recovery   |&lt;br /&gt;
    |                    |                        | only)             |&lt;br /&gt;
    | Cold-probe cadence | 100 ms (rx-driven;     | Pre-srtt RTTP     |&lt;br /&gt;
    |                    |  see Section 12)       | rate              |&lt;br /&gt;
    | DELT_RDV           | 100 ms                 | RDVS emit cadence |&lt;br /&gt;
    | MAX_RDV            | 1 s                    | RDVS give-up      |&lt;br /&gt;
    | Delayed-ACK fire   | 2 * TICTIME (TICTIME   | Fired after the   |&lt;br /&gt;
    |                    |  = FRCT tick gran-     | first in-order    |&lt;br /&gt;
    |                    |  ularity, default      | DATA arrival;     |&lt;br /&gt;
    |                    |  5 ms; 2*TICTIME       | tick is build-    |&lt;br /&gt;
    |                    |  = 10 ms by default)   | tunable           |&lt;br /&gt;
    | NACK send cooldown | srtt when an srtt      | Pre-DRF NACK      |&lt;br /&gt;
    |                    |  sample exists, else   | rate-limit        |&lt;br /&gt;
    |                    |  100 ms                |                   |&lt;br /&gt;
    | MAX_SDU            | 1 MiB                  | Max reassembled   |&lt;br /&gt;
    |                    |                        | SDU; configurable |&lt;br /&gt;
    |                    |                        | per flow          |&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
headsz / tailsz and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (snd_cr.seqno == snd_cr.lwe).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
snd_cr.inact AND the pipe is empty (snd_cr.seqno == snd_cr.lwe),&lt;br /&gt;
seqno_rotate() rolls a random new seqno before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(now - rcv_cr.act &amp;gt; rcv_cr.inact), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the rq[] slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per Section 3); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    1. If the SDU exceeds (frag_mtu - data_hdr_len), the caller&lt;br /&gt;
       (dev.c) fans it out into ceil(count / (frag_mtu -&lt;br /&gt;
       data_hdr_len)) fragments, each emitted via frcti_snd as its&lt;br /&gt;
       own DATA packet with a per-fragment role (Section 7.2);&lt;br /&gt;
       both FRTX and best-effort flows fragment.  Raw flows (no&lt;br /&gt;
       FRCP engagement, qos.service == SVC_RAW) carry no PCI and&lt;br /&gt;
       return -EMSGSIZE for any SDU larger than one packet at the&lt;br /&gt;
       layer below.  An SDU that fits in a single packet is sent&lt;br /&gt;
       as SOLE.  frcti_snd reserves PCI head room; sets DATA, plus&lt;br /&gt;
       DRF when the pipe is empty (snd_cr.seqno == snd_cr.lwe).&lt;br /&gt;
    2. seqno_rotate() if past sender inactivity and the pipe is&lt;br /&gt;
       empty (Section 4).&lt;br /&gt;
    3. Advertise FC (pci.window = frcti_advert_rwe(frcti), i.e.&lt;br /&gt;
       rcv_cr.rwe clamped to rcv_cr.lwe + ring_seq_cap in stream&lt;br /&gt;
       mode) when the receiver side is recent: now - rcv_cr.act&lt;br /&gt;
       &amp;lt; rcv_cr.inact.&lt;br /&gt;
    4. Reliable mode (FRTX): leave snd_cr.lwe where it is; reset&lt;br /&gt;
       the slot at RQ_SLOT(seqno) (snd_slots[p].time = now,&lt;br /&gt;
       snd_slots[p].flags = 0); queue an rxm_entry (saves a packet&lt;br /&gt;
       copy, arms a wheel timer at now + (rto &amp;lt;&amp;lt; rto_mul)).&lt;br /&gt;
       Piggyback ACK (pci.ackno = rcv_cr.lwe) while the a-timer&lt;br /&gt;
       for the most recent received DATA packet has not yet&lt;br /&gt;
       expired (now - rcv_cr.act &amp;lt;= t_a); on piggyback, set&lt;br /&gt;
       rcv_cr.seqno = rcv_cr.lwe so the next delayed-ACK fire is&lt;br /&gt;
       suppressed.  See Section 8 for t_a / t_r semantics.&lt;br /&gt;
    5. Best-effort mode (no FRTX): advance snd_cr.lwe immediately&lt;br /&gt;
       (snd_cr.lwe = snd_cr.lwe + 1, snd_cr.rwe = snd_cr.lwe +&lt;br /&gt;
       RQ_SIZE); no retransmit state.  No send-side RTT probe is&lt;br /&gt;
       armed in this mode (rtt_probe_arm requires an in-flight&lt;br /&gt;
       seqno, which best-effort never has); the rx-driven cold&lt;br /&gt;
       seeder in frcti_rcv is the only probe path.&lt;br /&gt;
    6. In reliable mode, optionally arm an RTT probe (Section 12).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of frcti_rcv before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - KA   : refresh t_ka_rcv, honour piggybacked ACK.&lt;br /&gt;
  - RTTP : probe (echo back nonce) or echo (verify nonce, sample&lt;br /&gt;
           RTT).&lt;br /&gt;
  - NACK : pre-DRF, sender-side handler.  See Section 9.&lt;br /&gt;
  - RDVS : reply with a bare FC packet (ackno = 0); rdlock only.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow frcti.lock held for writing&lt;br /&gt;
(pthread_rwlock_wrlock) unless noted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  rcv_inact_check&lt;br /&gt;
      Only meaningful when the receive side is stale.  On DRF&lt;br /&gt;
      (Data Run Flag): release rq[] slots, rebase rcv_cr, continue.&lt;br /&gt;
      On stale DATA without DRF: fire a pre-DRF NACK if cooldown&lt;br /&gt;
      allows (Section 9), then discard the packet; on cooldown,&lt;br /&gt;
      drop without sending a NACK (a pending cumulative ACK from&lt;br /&gt;
      drop_packet may still go out).  Non-DATA, non-DRF arrivals&lt;br /&gt;
      bypass rcv_inact_check entirely; pure-DRF stale arrivals fall&lt;br /&gt;
      through after the DRF rebase branch.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  DATA-only act refresh&lt;br /&gt;
      Refresh rcv_cr.act only when FRCT_DATA is set, so that non-DATA&lt;br /&gt;
      packets never block the next DRF rebase.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Wire-dup gate&lt;br /&gt;
      Before flag-driven dispatch, drop wire-duplicate ACKs and&lt;br /&gt;
      wire-duplicate DATA (is_dup_ack / is_dup_data).  The DATA&lt;br /&gt;
      check is bypassed for FRCT_RXM-bearing arrivals so the&lt;br /&gt;
      piggybacked ACK / SACK / FC carried on a retransmitted DATA&lt;br /&gt;
      at an already-ACK&#039;d seqno is still applied; the stale-in-&lt;br /&gt;
      window branch below then drops the packet.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ACK&lt;br /&gt;
      Drop ACKs whose ackno falls outside (snd_cr.lwe, snd_cr.seqno].&lt;br /&gt;
      If ackno == snd_cr.lwe (non-advancing cumulative ACK), drive&lt;br /&gt;
      RACK fast-retransmit consideration (Section 8).  Otherwise&lt;br /&gt;
      advance snd_cr.lwe = ackno, collapse rto_mul to 0 (Karn-gated&lt;br /&gt;
      by SND_RTX on the just-acknowledged slot, the old head-of-&lt;br /&gt;
      line), reset dup_thresh to 0, update t_latest_ack to the&lt;br /&gt;
      send-time of the slot at ackno-1 (consumed by RACK and SACK&lt;br /&gt;
      below), decay reo_wnd_mult per RFC 8985 sec. 6.2 step 4,&lt;br /&gt;
      exit NewReno-careful recovery (see Section 8) on&lt;br /&gt;
      ackno &amp;gt;= recovery_high or ackno == snd_cr.seqno, and feed an&lt;br /&gt;
      RTT sample if eligible (Section 12).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  SACK&lt;br /&gt;
      Walk the block list.  For each block (a present range above&lt;br /&gt;
      lwe) NULL out snd_slots[k].rxm, clear the slot&#039;s per-send&lt;br /&gt;
      flags, and advance t_latest_ack to the latest send-time&lt;br /&gt;
      covered (the Forward Acknowledgement / fack equivalent,&lt;br /&gt;
      Mathis &amp;amp; Mahdavi 1996); the first block whose start&lt;br /&gt;
      clamps to snd_cr.lwe skips this fack update so that a head-&lt;br /&gt;
      of-line clamp does not falsely advance fack.  For un-SACKed&lt;br /&gt;
      gaps below hi_sacked, stage a retransmit per slot that is&lt;br /&gt;
      (1) still owned (rxm != NULL), (2) not already SND_FAST_RXM,&lt;br /&gt;
      (3) not aged out past t_r, and (4) either outside the RACK&lt;br /&gt;
      reorder window R OR with dup_thresh &amp;gt;= DUP_THRESH (the RFC&lt;br /&gt;
      8985 sec. 6.2 hybrid trigger).  Mark the slot SND_FAST_RXM&lt;br /&gt;
      and NULL the rxm at stage time.  Capped at SACK_RXM_MAX&lt;br /&gt;
      staged retransmits per receive pass; what&#039;s left rides the&lt;br /&gt;
      next SACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  FC&lt;br /&gt;
      Bump snd_cr.rwe (clamped to lwe + RQ_SIZE, never shrinks)&lt;br /&gt;
      and mark window open.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  DATA&lt;br /&gt;
      Bounds-check seqno against window.  On stale-dup&lt;br /&gt;
      (seqno &amp;lt; rcv_cr.lwe), set rcv_cr.seqno = seqno to force a&lt;br /&gt;
      fresh ACK on the next ack_snd, then drop.  On accept: both&lt;br /&gt;
      FRTX and best-effort stash the packet-buffer index into&lt;br /&gt;
      rq[seqno mod RQ_SIZE].  Fragments stash unchanged - the role&lt;br /&gt;
      bits are inspected only at consume time (Section 7.2).  On&lt;br /&gt;
      out-of-order arrival, build a SACK reply if not rate-limited&lt;br /&gt;
      (per Section 3) and not deduplicated against the previous&lt;br /&gt;
      (rcv_cr.lwe, n_blocks) pair; D-SACK reports always bypass the&lt;br /&gt;
      dedup.  If both rate-limit and dedup suppress the reply,&lt;br /&gt;
      neither SACK nor delayed-ACK fires (the sender picks up the&lt;br /&gt;
      gap on its next ACK).  On in-order arrival, arm the delayed-&lt;br /&gt;
      ACK timer.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  drop_packet exit&lt;br /&gt;
      Releases the per-packet shared-memory buffer (spb), then&lt;br /&gt;
      calls ack_snd synchronously after the spb release to surface&lt;br /&gt;
      any pending cumulative ACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
flow_read returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
frcti_consume on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in Section 16.  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields -EAGAIN; an oversized run yields -EMSGSIZE (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring (Section 7.2 skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no frcti, so flow_read returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via qos.service == SVC_RAW at flow allocation,&lt;br /&gt;
which suppresses frcti creation.)&lt;br /&gt;
&lt;br /&gt;
frcti_pdu_ready is the no-advance peek used by fevent (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the poll(2)-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at rcv_cr.rwe - RQ_SIZE; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and frcti_consume is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (flow_write_frag).  An SDU larger than&lt;br /&gt;
(frag_mtu - PCI) is split into ceil(count / (frag_mtu - PCI))&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
seqno and a per-fragment role flag pair (Section 1.2).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +------+--------+&lt;br /&gt;
    | i    | Role   |&lt;br /&gt;
    +------+--------+&lt;br /&gt;
    | n=1  | SOLE   |&lt;br /&gt;
    | i=0  | FIRST  |&lt;br /&gt;
    | i=n-1| LAST   |&lt;br /&gt;
    | else | MID    |&lt;br /&gt;
    +------+--------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (off &amp;gt; 0) or&lt;br /&gt;
the underlying error (off == 0).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (-EMSGSIZE).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s seqno flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same seqno&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no rxm state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into rq[seqno] unchanged; role bits&lt;br /&gt;
are read only at consume time.  frag_run_inspect, called from&lt;br /&gt;
frcti_consume, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered seqno base = rcv_cr.rwe - RQ_SIZE (equal to rcv_cr.lwe&lt;br /&gt;
only when no partial run is in progress; during a partial run lwe&lt;br /&gt;
has already advanced past base).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
    | Outcome       | Cause                                       |&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
    | DELIVER (n)   | rq[base]=SOLE (n=1), or rq[base]=FIRST and  |&lt;br /&gt;
    |               | a LAST follows in slots [base+1..base+n-1]  |&lt;br /&gt;
    |               | with all intermediate roles in {MID,FIRST,  |&lt;br /&gt;
    |               | LAST} contiguous.                           |&lt;br /&gt;
    | DROP (n)      | rq[base] is MID or LAST without a preceding |&lt;br /&gt;
    |               | FIRST (n=1); a FIRST..[non-LAST]..new-FIRST |&lt;br /&gt;
    |               | or new-SOLE mid-run (drop the broken prefix |&lt;br /&gt;
    |               | with n = run length minus 1, so the new     |&lt;br /&gt;
    |               | FIRST/SOLE stays); or, on best-effort       |&lt;br /&gt;
    |               | flows, a gap at base with a FIRST/SOLE      |&lt;br /&gt;
    |               | later in the ring (drop up to the new run   |&lt;br /&gt;
    |               | start).                                     |&lt;br /&gt;
    | NOT_READY     | rq[base] absent or FIRST..[non-LAST] with   |&lt;br /&gt;
    |               | no later FIRST/SOLE in the ring (FRTX waits |&lt;br /&gt;
    |               | for retx; best-effort waits for arrival).   |&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
DELIVER triggers frag_gather: a scatter-gather memcpy of the n&lt;br /&gt;
consecutive fragments at rq[base..base+n-1] directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (spb) is&lt;br /&gt;
released and rwe advances by n.  lwe was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; frag_gather&lt;br /&gt;
only restores the fixed-width invariant rwe == lwe + RQ_SIZE.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
DROP advances rwe past the broken prefix (releasing the spbs)&lt;br /&gt;
and pulls lwe up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new base.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;gt; max_rcv_sdu, sum&lt;br /&gt;
&amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with -EMSGSIZE.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and frag_run_inspect returns NOT_READY.&lt;br /&gt;
On best-effort flows the gap is permanent, so frag_run_inspect&lt;br /&gt;
scans forward in the ring for the next FIRST or SOLE; if one is&lt;br /&gt;
visible within RQ_SIZE, it returns DROP for the broken prefix and&lt;br /&gt;
the consume loop retries at the new lwe.  Memory hold is bounded&lt;br /&gt;
by RQ_SIZE; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one SOLE per SDU)&lt;br /&gt;
see no extra wait: any later SOLE makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
Section 15):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - t_a (a-timer): upper bound on ACK delay.  An ACK for a received&lt;br /&gt;
    DATA packet MUST be emitted within t_a of receipt; an attempt&lt;br /&gt;
    to send an ACK after the a-timer has expired is suppressed&lt;br /&gt;
    (the sender&#039;s RTO is already in motion).&lt;br /&gt;
  - t_r (r-timer): upper bound on retransmission.  A given DATA&lt;br /&gt;
    packet MUST NOT be retransmitted after t_r has elapsed since&lt;br /&gt;
    its first send (t0); when the bound is hit, the flow is&lt;br /&gt;
    declared down (raising the Ouroboros asynchronous flow&lt;br /&gt;
    condition ACL_FLOWDOWN, which marks the flow dead to both&lt;br /&gt;
    endpoints) rather than retransmitted again.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX seqno owns one rxm_entry, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  RTO timer&lt;br /&gt;
      On fire (rxm_due), re-emit with FRCT_RXM, mark SND_RTX&lt;br /&gt;
      (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-&lt;br /&gt;
      line (HoL) slot only) bump rto_mul up to MAX_RTO_MUL.  Wheel&lt;br /&gt;
      deadline is t_send + (rto &amp;lt;&amp;lt; rto_mul).  Re-armed unless&lt;br /&gt;
      consumed.  The RTO timer also clears SND_FAST_RXM (re-arming&lt;br /&gt;
      fast-retransmit eligibility), resets reo_wnd_mult to 1 on a&lt;br /&gt;
      HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks&lt;br /&gt;
      the flow ACL_FLOWDOWN if its frct_tx call fails.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  r-timer guard&lt;br /&gt;
      Before any retransmit attempt, check (now - t0) against t_r.&lt;br /&gt;
      If exceeded, the slot is no longer eligible for retransmit.&lt;br /&gt;
      Only the RTO timer (rxm_due) treats r-timer expiry as&lt;br /&gt;
      terminal: it marks the flow ACL_FLOWDOWN (peer unreachable).&lt;br /&gt;
      Fast-retransmit, SACK-driven retransmit, and NACK-driven&lt;br /&gt;
      head-of-line re-emit silently skip aged-out slots and defer&lt;br /&gt;
      the flow-down decision to the next RTO fire.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
      On a non-advancing cumulative ACK with the scoreboard&lt;br /&gt;
      advanced, fire one fast retransmit when EITHER (a) the head-&lt;br /&gt;
      of-line slot&#039;s latest send is older than the RACK reorder&lt;br /&gt;
      window R (Section 3) and not yet aged out, OR (b) the SACK&lt;br /&gt;
      dup-thresh count above snd_cr.lwe reaches DUP_THRESH (= 3,&lt;br /&gt;
      RFC 8985 sec. 6.2 step 4).  Fires at most once per non-&lt;br /&gt;
      advancing cumulative-ACK value, gated by rack_fired_lwe (the&lt;br /&gt;
      snd_cr.lwe at which fast-retransmit last fired).  Set&lt;br /&gt;
      SND_FAST_RXM on the slot (one-shot per-slot gate) and enter&lt;br /&gt;
      NewReno-style careful recovery (see NewReno below in this&lt;br /&gt;
      section).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      The RACK reorder window R uses the RFC 8985 sec. 6.2 form&lt;br /&gt;
      R = MIN(reo_wnd_mult * min_RTT / 4, SRTT) with a&lt;br /&gt;
      MIN_REORDER_NS = 250 us floor.  Before the first RTT sample&lt;br /&gt;
      seeds min_rtt, R falls back to MIN(reo_wnd_mult * SRTT / 4,&lt;br /&gt;
      SRTT), still floored at MIN_REORDER_NS (consistent with the&lt;br /&gt;
      windowed-minimum fallback described in Section 12).  min_rtt&lt;br /&gt;
      is a windowed minimum over the last MIN_RTT_WIN_NS = 5 min of&lt;br /&gt;
      RTT samples (matches the Linux tcp_min_rtt_wlen default) so a&lt;br /&gt;
      route change to a longer path eventually re-anchors the&lt;br /&gt;
      reorder window without relying on reo_wnd_mult growth alone.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  SACK-driven retransmit&lt;br /&gt;
      For each gap below hi_sacked whose slot is (1) still owned,&lt;br /&gt;
      (2) not already SND_FAST_RXM, (3) not aged out past t_r, and&lt;br /&gt;
      (4) either outside the RACK window R OR with dup_thresh &amp;gt;=&lt;br /&gt;
      DUP_THRESH (same hybrid as fast-retransmit, see Section 6.2),&lt;br /&gt;
      re-emit.  Each SACK-driven retransmit re-arms a fresh rxm so&lt;br /&gt;
      a lost retransmit can still be recovered by its own RTO&lt;br /&gt;
      timer.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  NewReno&lt;br /&gt;
      On entry, recovery_high = snd_cr.seqno + RTT_QUARANTINE.&lt;br /&gt;
      Exit when ackno &amp;gt;= recovery_high or ackno == snd_cr.seqno&lt;br /&gt;
      (the latter means everything sent has been acknowledged).&lt;br /&gt;
      seqno_rotate also clears recovery.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds&lt;br /&gt;
(snd_cr.inact &amp;gt; rcv_cr.inact), so a receiver can detect &amp;quot;stale data&lt;br /&gt;
run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the&lt;br /&gt;
receiver-driven nudge that asks the sender to re-transmit the head&lt;br /&gt;
of the run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Send (frcti_nack_snd, called by frcti_rcv when rcv_inact_check&lt;br /&gt;
        returns FRCT_INACT_NEED_NACK)&lt;br /&gt;
      When an incoming DATA packet has no DRF and rcv-side activity&lt;br /&gt;
      is older than rcv_cr.inact, the receiver emits a bare packet&lt;br /&gt;
      with flags = FRCT_NACK and seqno = arrival_seqno - 1&lt;br /&gt;
      (informational only, not consulted by the receive handler).&lt;br /&gt;
      The cooldown in Section 3 rate-limits the burst.  Non-DATA&lt;br /&gt;
      non-DRF arrivals bypass rcv_inact_check entirely; non-DATA&lt;br /&gt;
      DRF still rebases via the DRF branch.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Receive (frcti_nack_rcv)&lt;br /&gt;
      Dispatched in the early-exit branch (Section 6.1), before&lt;br /&gt;
      rcv_inact_check.  The sender copies the head-of-line (HoL)&lt;br /&gt;
      rxm packet, marks the slot SND_RTX | SND_FAST_RXM (Karn-&lt;br /&gt;
      suppress next ACK, one-shot fast-rxm gate), sets rtt_lwe =&lt;br /&gt;
      snd_cr.lwe + 1, and re-emits via fast_rxm_send with FRCT_RXM&lt;br /&gt;
      and a refreshed ackno.  The original rxm_entry and its RTO&lt;br /&gt;
      timer are left armed - the NACK emit is additive to the&lt;br /&gt;
      normal retransmit machinery, not a replacement.  No-op if&lt;br /&gt;
      nothing is in flight, the HoL slot has aged past t_r, or&lt;br /&gt;
      the HoL rxm pointer has been cleared by SACK or RACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NACK serves two roles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. Lost first-of-run (DRF) packet recovery.  Required.  Until&lt;br /&gt;
     the DRF packet arrives, the receiver cannot rebase its&lt;br /&gt;
     window, so any subsequent in-flight packets look stale to&lt;br /&gt;
     the receiver.  The NACK fires the moment the second&lt;br /&gt;
     packet arrives at a stale receiver, telling the sender to&lt;br /&gt;
     re-emit the HoL (DRF) packet at NACK-cooldown latency rather&lt;br /&gt;
     than waiting for the initial RTO (which is the configured&lt;br /&gt;
     default until srtt is seeded by the first probe round-trip).&lt;br /&gt;
  2. General loss-recovery accelerator.  When loss is detected&lt;br /&gt;
     receiver-first, the NACK skips one RTO of latency relative to&lt;br /&gt;
     waiting for the sender&#039;s RTO to fire.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In both cases the existing rxm_entry and its RTO timer are left&lt;br /&gt;
armed, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is ackno = rcv_cr.lwe.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet (Section 1.3) whose payload lists&lt;br /&gt;
*present* blocks above lwe (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per Section 3 and suppressed when&lt;br /&gt;
neither lwe nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as block[0] of an&lt;br /&gt;
otherwise normal SACK frame (see Section 1.3 for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - DATA arrival with seqno &amp;lt; rcv_cr.lwe, both wire-dup (no RXM,&lt;br /&gt;
    is_dup_data path) and retransmit (RXM, post-FC branch)&lt;br /&gt;
    (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
  - rq_accept conflict, slot already occupied in [lwe, rwe)&lt;br /&gt;
    (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal ack_snd path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the TICTIME&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per Section 3&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
seqno, (2) rcv side is inactive (older than t_a), or (3) the&lt;br /&gt;
sender just sent within TICTIME.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises rwe in every FC field.  The sender treats&lt;br /&gt;
its snd_cr.rwe as the absolute right edge: when&lt;br /&gt;
snd_cr.seqno &amp;gt;= snd_cr.rwe the window is closed and flow_write&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence DELT_RDV); the receiver replies with&lt;br /&gt;
a bare FC packet (ackno = 0) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than MAX_RDV the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
rwe is clamped to lwe + RQ_SIZE on receipt and MUST NOT shrink:&lt;br /&gt;
a backward rwe is silently clamped to the current snd_cr.rwe;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes (Section 1.4) carry a 32-bit probe_id (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of RTTP_RING in-flight probes is&lt;br /&gt;
kept; an echo whose (id, nonce) doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to RTT_CLAMP_MUL * srtt&lt;br /&gt;
(compile-time RTT_CLAMP_MUL = 16) once srtt is seeded; the first&lt;br /&gt;
cold-probe sample feeds rtt_update raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Cold (no srtt yet): the receive path arms at most one probe&lt;br /&gt;
    per 100 ms via frcti_rcv_probe (PROBE_DUE_COLD); arming&lt;br /&gt;
    requires an incoming packet.  Active send-path arming bails&lt;br /&gt;
    while srtt == 0.&lt;br /&gt;
  - Warm (rtt_probe_arm, called from frcti_snd): outstanding&lt;br /&gt;
    data (snd_cr.seqno &amp;gt; snd_cr.lwe), AND at least 2 * srtt&lt;br /&gt;
    since t_rcv_rtt (last RTT receive of any kind), AND at&lt;br /&gt;
    least srtt since t_snd_probe (last probe emit).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric mdev estimator&lt;br /&gt;
(FRCT_LINUX_RTT_ESTIMATOR, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  srtt is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); mdev floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;lt;&amp;lt; MDEV_MUL))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the 2 * srtt floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per Section 3.&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (frcti_ack_rcv -&amp;gt; rtt_sample_eligible), beyond&lt;br /&gt;
the cum-ACK advance gate in frcti_ack_rcv (ackno &amp;gt; lwe and&lt;br /&gt;
ackno &amp;lt;= seqno), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry FRCT_RXM; HoL slot&#039;s SND_RTX bit clear; slot&#039;s rxm&lt;br /&gt;
pointer non-NULL (not SACK-consumed); lwe not below the rtt_lwe&lt;br /&gt;
fence; srtt already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds RACK.min_RTT (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than MIN_RTT_WIN_NS (5 min, matches Linux&lt;br /&gt;
tcp_min_rtt_wlen) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors min_RTT after at most one window).  Seeded from&lt;br /&gt;
rtt_hint at rtt_init; 0 acts as the unset sentinel and the base&lt;br /&gt;
in rack_reorder_window falls back from min_RTT to SRTT (so&lt;br /&gt;
R = mult * SRTT/4, capped at SRTT, floored at MIN_REORDER_NS)&lt;br /&gt;
until the first sample.  See Section 6.2.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When qs.timeout &amp;gt; 0 a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses rcv_cr.act for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    deadline = min(snd_act + qs.timeout/4,&lt;br /&gt;
                   rcv_act + qs.timeout)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to now + qs.timeout/4 if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (ka_snd) the peer-dead test&lt;br /&gt;
uses max(rcv_cr.act, t_ka_rcv) so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - If now - max(rcv_cr.act, t_ka_rcv) &amp;gt; qs.timeout, mark the flow&lt;br /&gt;
    ACL_FLOWPEER and notify the per-process flow-event set&lt;br /&gt;
    (proc.fqset) with FLOW_PEER.&lt;br /&gt;
  - Else if snd_idle &amp;gt; qs.timeout/4, emit a bare KA | ACK&lt;br /&gt;
    (ackno = rcv_cr.lwe) and re-arm.&lt;br /&gt;
  - Else just re-arm.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: rx_rb and tx_rb are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises ACL_FLOWDOWN on both (route is&lt;br /&gt;
broken); keepalive raises ACL_FLOWPEER on rx_rb only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps tx_rb usable) -&lt;br /&gt;
distinct ACLs.  qs.timeout == 0 disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On flow_dealloc, frcti_dealloc computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; flow_dealloc&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when rcv_cr.lwe != rcv_cr.seqno (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within t_a (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
FRCTFLINGER is honoured only when snd_cr.lwe &amp;lt; edge, where edge =&lt;br /&gt;
snd_fin_seqno after FIN has been sent in stream mode and&lt;br /&gt;
snd_cr.seqno otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in flow_dealloc&#039;s while (FRCTI_LINGERING) loop, not in&lt;br /&gt;
frcti_dealloc.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  flow_write pumps rx_rb on every call (via&lt;br /&gt;
flow_wait_window -&amp;gt; flow_drain_rx_nb) and additionally blocks on&lt;br /&gt;
rx_rb when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after t_mpl + a + r of silence), the DRF marker, and the&lt;br /&gt;
t_mpl / t_a / t_r timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified `flow_alloc(name, qos, ...)` primitive and its&lt;br /&gt;
multi-axis QoS-cube argument (Section 2.2) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| FRCP mechanism         | Heritage         | Reference / note       |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Random new seqno on    | TCP ISN          | RFC 6528 (Gont &amp;amp;       |&lt;br /&gt;
| seqno_rotate           |                  | Bellovin, 2012).       |&lt;br /&gt;
|                        |                  | QUIC PN-space reset    |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 12.3)   |&lt;br /&gt;
|                        |                  | is a structural        |&lt;br /&gt;
|                        |                  | analogue.              |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Cumulative ACK,        | TCP              | RFC 793 / RFC 9293     |&lt;br /&gt;
| left-window-edge       |                  |                        |&lt;br /&gt;
| advance                |                  |                        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Receive window with    | TCP              | RFC 793 sec. 3.7 /     |&lt;br /&gt;
| non-shrink rule        |                  | RFC 9293 sec. 3.8.6;   |&lt;br /&gt;
|                        |                  | RFC 1122 sec. 4.2.2.16 |&lt;br /&gt;
|                        |                  | for the explicit non-  |&lt;br /&gt;
|                        |                  | shrink prohibition     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Modular seqno          | TCP              | RFC 793 sec. 3.3 /     |&lt;br /&gt;
| arithmetic             |                  | RFC 9293 sec. 3.4      |&lt;br /&gt;
| (before/after helpers) |                  |                        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Selective ACK block    | TCP              | RFC 2018 (Mathis et    |&lt;br /&gt;
| list                   |                  | al., 1996).  Encoded   |&lt;br /&gt;
|                        |                  | as a typed FRCP packet |&lt;br /&gt;
|                        |                  | rather than a TCP      |&lt;br /&gt;
|                        |                  | option, so framing is  |&lt;br /&gt;
|                        |                  | closer to QUIC ACK     |&lt;br /&gt;
|                        |                  | frames.  D-SACK (RFC   |&lt;br /&gt;
|                        |                  | 2883) carried in-band  |&lt;br /&gt;
|                        |                  | as block[0]; see       |&lt;br /&gt;
|                        |                  | Section 1.3.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| NewReno-careful        | TCP              | RFC 6582 (Henderson    |&lt;br /&gt;
| recovery with          |                  | et al., 2012); QUIC    |&lt;br /&gt;
| recovery_high gate     |                  | builds on the same     |&lt;br /&gt;
|                        |                  | model in RFC 9002      |&lt;br /&gt;
|                        |                  | sec. 7.3.2.  Cwnd half |&lt;br /&gt;
|                        |                  | absent (CC in IPCP).   |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| RACK reordering        | TCP              | RFC 8985 (Cheng et     |&lt;br /&gt;
| window for fast        |                  | al., 2021).  FRCP      |&lt;br /&gt;
| retransmit             |                  | R = MIN(reo_wnd_mult * |&lt;br /&gt;
|                        |                  | min_RTT / 4, SRTT)     |&lt;br /&gt;
|                        |                  | with a MIN_REORDER_NS  |&lt;br /&gt;
|                        |                  | = 250 us floor against |&lt;br /&gt;
|                        |                  | srtt collapse; matches |&lt;br /&gt;
|                        |                  | RFC 8985 sec. 6.2 and  |&lt;br /&gt;
|                        |                  | Linux tcp_rack_reo_wnd.|&lt;br /&gt;
|                        |                  | DSACK-driven           |&lt;br /&gt;
|                        |                  | reo_wnd_mult (sec. 6.2 |&lt;br /&gt;
|                        |                  | step 4) is adopted;    |&lt;br /&gt;
|                        |                  | see Section 1.3 for    |&lt;br /&gt;
|                        |                  | the wire encoding.     |&lt;br /&gt;
|                        |                  | The hybrid RACK-or-    |&lt;br /&gt;
|                        |                  | DUP_THRESH trigger     |&lt;br /&gt;
|                        |                  | from RFC 8985 sec. 6.2 |&lt;br /&gt;
|                        |                  | step 4 is adopted      |&lt;br /&gt;
|                        |                  | (Section 8).  QUIC&#039;s   |&lt;br /&gt;
|                        |                  | analogue in RFC 9002   |&lt;br /&gt;
|                        |                  | sec. 6.1.2 uses        |&lt;br /&gt;
|                        |                  | max(srtt, latest_rtt)  |&lt;br /&gt;
|                        |                  | as the base.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Karn&#039;s algorithm:      | TCP              | Karn &amp;amp; Partridge,      |&lt;br /&gt;
| no RTT sample on       |                  | &amp;quot;Improving Round-Trip  |&lt;br /&gt;
| retransmits, RTO-      |                  | Time Estimates in      |&lt;br /&gt;
| collapse freeze        |                  | Reliable Transport     |&lt;br /&gt;
|                        |                  | Protocols&amp;quot;, SIGCOMM    |&lt;br /&gt;
|                        |                  | 1987; RFC 6298 sec. 3. |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| RTO formula            | TCP              | RFC 6298 (Paxson et    |&lt;br /&gt;
| RTO = max(RTO_MIN,     |                  | al., 2011).  RTO_MIN = |&lt;br /&gt;
| srtt + (mdev &amp;lt;&amp;lt;        |                  | 5 ms is below RFC 6298 |&lt;br /&gt;
| MDEV_MUL))             |                  | sec. 2.4&#039;s 1 s SHOULD- |&lt;br /&gt;
|                        |                  | floor - a recursive-   |&lt;br /&gt;
|                        |                  | layer choice.          |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Linux asymmetric mdev  | Linux kernel     | tcp_rtt_estimator() in |&lt;br /&gt;
| estimator (default)    |                  | net/ipv4/tcp_input.c;  |&lt;br /&gt;
|                        |                  | the if(delta&amp;lt;0) m&amp;gt;&amp;gt;=3  |&lt;br /&gt;
|                        |                  | dampening is a         |&lt;br /&gt;
|                        |                  | kernel divergence from |&lt;br /&gt;
|                        |                  | RFC 6298.  RFC 6298    |&lt;br /&gt;
|                        |                  | EWMA available behind  |&lt;br /&gt;
|                        |                  | a compile flag.        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Delayed ACK with rate  | TCP              | RFC 813 (Clark, 1982); |&lt;br /&gt;
| suppression            |                  | RFC 1122 sec. 4.2.3.2; |&lt;br /&gt;
|                        |                  | RFC 5681 sec. 4.2.     |&lt;br /&gt;
|                        |                  | Single-deadline        |&lt;br /&gt;
|                        |                  | coalescing rather than |&lt;br /&gt;
|                        |                  | &amp;quot;ack-every-other-      |&lt;br /&gt;
|                        |                  | segment&amp;quot;.              |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Zero-window-probe /    | TCP              | RFC 1122 sec.          |&lt;br /&gt;
| persist-timer          |                  | 4.2.2.17 / RFC 9293    |&lt;br /&gt;
| analogue (RDVS)        |                  | sec. 3.8.6.1.  RDVS    |&lt;br /&gt;
|                        |                  | solicits an FC reply,  |&lt;br /&gt;
|                        |                  | distinct from QUIC     |&lt;br /&gt;
|                        |                  | DATA_BLOCKED (RFC 9000 |&lt;br /&gt;
|                        |                  | sec. 19.12), which is  |&lt;br /&gt;
|                        |                  | one-way notification.  |&lt;br /&gt;
|                        |                  | MAX_RDV give-up        |&lt;br /&gt;
|                        |                  | departs from TCP.      |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Multiplexed control    | SCTP / QUIC      | SCTP chunk bundling    |&lt;br /&gt;
| on a single PCI        |                  | (RFC 9260 sec. 6.10);  |&lt;br /&gt;
|                        |                  | QUIC frame             |&lt;br /&gt;
|                        |                  | multiplexing (RFC 9000 |&lt;br /&gt;
|                        |                  | sec. 12.4).  Cleaner   |&lt;br /&gt;
|                        |                  | fit than TCP&#039;s         |&lt;br /&gt;
|                        |                  | separate-flag-bits     |&lt;br /&gt;
|                        |                  | design.                |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| ACK ranges as          | QUIC             | QUIC ACK frame (RFC    |&lt;br /&gt;
| multiple discontiguous |                  | 9000 sec. 19.3).  FRCP |&lt;br /&gt;
| acked blocks           |                  | SACK is conceptually   |&lt;br /&gt;
|                        |                  | QUIC-frame-shaped      |&lt;br /&gt;
|                        |                  | even though encoded    |&lt;br /&gt;
|                        |                  | as absolute            |&lt;br /&gt;
|                        |                  | [start,end] pairs.     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Nonce-authenticated    | QUIC             | PATH_CHALLENGE /       |&lt;br /&gt;
| active RTT / liveness  | PATH_CHALLENGE   | PATH_RESPONSE (RFC     |&lt;br /&gt;
| probing (RTTP)         |                  | 9000 sec. 8.2,         |&lt;br /&gt;
|                        |                  | sec. 19.17, sec.       |&lt;br /&gt;
|                        |                  | 19.18).  WebRTC ICE    |&lt;br /&gt;
|                        |                  | consent-freshness      |&lt;br /&gt;
|                        |                  | (RFC 7675) is the      |&lt;br /&gt;
|                        |                  | same pattern.  QUIC&#039;s  |&lt;br /&gt;
|                        |                  | nonce is 8 octets;     |&lt;br /&gt;
|                        |                  | FRCP chooses 16.       |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Probing distinct from  | QUIC             | KA timer answers       |&lt;br /&gt;
| keepalive              |                  | &amp;quot;peer alive?&amp;quot;, RTTP    |&lt;br /&gt;
|                        |                  | answers &amp;quot;path          |&lt;br /&gt;
|                        |                  | measurable?&amp;quot;, as in    |&lt;br /&gt;
|                        |                  | QUIC PING (RFC 9000    |&lt;br /&gt;
|                        |                  | sec. 19.2) vs          |&lt;br /&gt;
|                        |                  | PATH_CHALLENGE.        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Bare KA + ACK          | QUIC / SCTP      | QUIC PING (RFC 9000    |&lt;br /&gt;
| keepalive packets      |                  | sec. 19.2); SCTP       |&lt;br /&gt;
|                        |                  | HEARTBEAT /            |&lt;br /&gt;
|                        |                  | HEARTBEAT-ACK (RFC     |&lt;br /&gt;
|                        |                  | 9260 sec. 8.3).  SCTP  |&lt;br /&gt;
|                        |                  | HEARTBEAT also carries |&lt;br /&gt;
|                        |                  | an opaque echoed blob, |&lt;br /&gt;
|                        |                  | structurally similar   |&lt;br /&gt;
|                        |                  | to FRCP RTTP.          |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| (FFGM, LFGM)           | SCTP             | RFC 9260 sec. 3.3.1    |&lt;br /&gt;
| fragment-role bits     |                  | DATA chunk B/E bits    |&lt;br /&gt;
| (Section 7.2)          |                  | encode the same four   |&lt;br /&gt;
|                        |                  | states (B+E=SOLE,      |&lt;br /&gt;
|                        |                  | B-only=FIRST, neither  |&lt;br /&gt;
|                        |                  | =MID, E-only=LAST).    |&lt;br /&gt;
|                        |                  | Each fragment carries  |&lt;br /&gt;
|                        |                  | its own seqno/TSN and  |&lt;br /&gt;
|                        |                  | is independently       |&lt;br /&gt;
|                        |                  | retransmitted.         |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Stream byte-offset     | QUIC             | QUIC STREAM frame      |&lt;br /&gt;
| reassembly             |                  | (RFC 9000 sec. 19.8)   |&lt;br /&gt;
| (Sections 1.5, 16)     |                  | uses Offset + Length   |&lt;br /&gt;
|                        |                  | varints; FRCP uses     |&lt;br /&gt;
|                        |                  | fixed 32-bit start /   |&lt;br /&gt;
|                        |                  | end.  One stream per   |&lt;br /&gt;
|                        |                  | flow vs QUIC&#039;s many    |&lt;br /&gt;
|                        |                  | streams multiplexed.   |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| FIN end-of-stream      | TCP / QUIC       | TCP FIN flag (RFC 9293 |&lt;br /&gt;
| marker                 |                  | sec. 3.1) closes one   |&lt;br /&gt;
| (Sections 1.2, 16)     |                  | half of the byte       |&lt;br /&gt;
|                        |                  | stream; QUIC STREAM    |&lt;br /&gt;
|                        |                  | frame FIN bit (RFC     |&lt;br /&gt;
|                        |                  | 9000 sec. 19.8) does   |&lt;br /&gt;
|                        |                  | the same per stream    |&lt;br /&gt;
|                        |                  | with an immutable      |&lt;br /&gt;
|                        |                  | final-size invariance  |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 4.5:    |&lt;br /&gt;
|                        |                  | the final size is      |&lt;br /&gt;
|                        |                  | fixed once observed).  |&lt;br /&gt;
|                        |                  | FRCP&#039;s FIN consumes    |&lt;br /&gt;
|                        |                  | one packet seqno (not  |&lt;br /&gt;
|                        |                  | one byte of stream     |&lt;br /&gt;
|                        |                  | space) and is          |&lt;br /&gt;
|                        |                  | idempotent on the      |&lt;br /&gt;
|                        |                  | sender side.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Stream byte-credit     | QUIC             | MAX_STREAM_DATA (RFC   |&lt;br /&gt;
| flow control           |                  | 9000 sec. 4.1, sec.    |&lt;br /&gt;
| (Section 16)           |                  | 19.10).  FRCP projects |&lt;br /&gt;
|                        |                  | a per-flow byte budget |&lt;br /&gt;
|                        |                  | onto the seqno-space   |&lt;br /&gt;
|                        |                  | rwe.  Single stream    |&lt;br /&gt;
|                        |                  | per flow collapses     |&lt;br /&gt;
|                        |                  | QUIC&#039;s MAX_DATA /      |&lt;br /&gt;
|                        |                  | MAX_STREAM_            |&lt;br /&gt;
|                        |                  | DATA distinction.      |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Header protection      | QUIC             | QUIC RFC 9001 sec. 5.4 |&lt;br /&gt;
| (encrypted seqnos)     |                  | applies header         |&lt;br /&gt;
|                        |                  | protection on top of   |&lt;br /&gt;
|                        |                  | AEAD to mask the       |&lt;br /&gt;
|                        |                  | packet number.  FRCP&#039;s |&lt;br /&gt;
|                        |                  | per-flow AEAD wrap     |&lt;br /&gt;
|                        |                  | (Section 16) is wider: |&lt;br /&gt;
|                        |                  | it encrypts the entire |&lt;br /&gt;
|                        |                  | PCI including seqno    |&lt;br /&gt;
|                        |                  | because the IPCP       |&lt;br /&gt;
|                        |                  | below already routes,  |&lt;br /&gt;
|                        |                  | so no destination      |&lt;br /&gt;
|                        |                  | connection-ID needs to |&lt;br /&gt;
|                        |                  | stay in clear (cf.     |&lt;br /&gt;
|                        |                  | RFC 9000 sec. 5.2).    |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Two-bit fragment role  | SCTP             | The (FFGM, LFGM) pair  |&lt;br /&gt;
| polarity               |                  | follows SCTP B/E       |&lt;br /&gt;
|                        |                  | (begin = 1 / end = 1)  |&lt;br /&gt;
|                        |                  | rather than IPv4 MF    |&lt;br /&gt;
|                        |                  | (RFC 791 sec. 3.2),    |&lt;br /&gt;
|                        |                  | which has the inverse  |&lt;br /&gt;
|                        |                  | polarity (MF = 1 means |&lt;br /&gt;
|                        |                  | NOT last).             |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Orthogonal reliability | SCTP             | PR-SCTP (RFC 3758,     |&lt;br /&gt;
| / ordering axes        |                  | per-message partial    |&lt;br /&gt;
| (Section 2.2)          |                  | reliability) and SCTP  |&lt;br /&gt;
|                        |                  | DATA U-bit (RFC 9260   |&lt;br /&gt;
|                        |                  | sec. 3.3.1, per-       |&lt;br /&gt;
|                        |                  | message unordered)     |&lt;br /&gt;
|                        |                  | are the closest        |&lt;br /&gt;
|                        |                  | precedents for         |&lt;br /&gt;
|                        |                  | decoupling reliability |&lt;br /&gt;
|                        |                  | from ordering; FRCP    |&lt;br /&gt;
|                        |                  | sets them per-flow     |&lt;br /&gt;
|                        |                  | rather than per-       |&lt;br /&gt;
|                        |                  | message.               |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Orthogonal CRC         | UDP-Lite         | RFC 3828 (Larzon et    |&lt;br /&gt;
| (qs.ber == 0)          |                  | al., 2004) lets the    |&lt;br /&gt;
|                        |                  | sender pick a per-     |&lt;br /&gt;
|                        |                  | packet Checksum        |&lt;br /&gt;
|                        |                  | Coverage and the       |&lt;br /&gt;
|                        |                  | receiver enforce a     |&lt;br /&gt;
|                        |                  | locally configured     |&lt;br /&gt;
|                        |                  | minimum (no in-band    |&lt;br /&gt;
|                        |                  | negotiation; sec. 3.1, |&lt;br /&gt;
|                        |                  | sec. 3.3).  FRCP       |&lt;br /&gt;
|                        |                  | gates a full CRC       |&lt;br /&gt;
|                        |                  | trailer on qs.ber == 0 |&lt;br /&gt;
|                        |                  | at flow setup.         |&lt;br /&gt;
|                        |                  | Contrast TCP / SCTP    |&lt;br /&gt;
|                        |                  | (mandatory checksum)   |&lt;br /&gt;
|                        |                  | and QUIC (AEAD         |&lt;br /&gt;
|                        |                  | subsumes CRC).         |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Setup-time service     | DCCP / SCTP /    | DCCP Service Codes     |&lt;br /&gt;
| negotiation            | QUIC             | (RFC 4340 sec. 8.1.2,  |&lt;br /&gt;
|                        |                  | RFC 5595); SCTP INIT   |&lt;br /&gt;
|                        |                  | parameters (RFC 9260   |&lt;br /&gt;
|                        |                  | sec. 3.3.2); QUIC      |&lt;br /&gt;
|                        |                  | transport parameters   |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 7.4).   |&lt;br /&gt;
|                        |                  | All negotiate service  |&lt;br /&gt;
|                        |                  | properties at          |&lt;br /&gt;
|                        |                  | connection setup; only |&lt;br /&gt;
|                        |                  | RINA&#039;s QoS cube        |&lt;br /&gt;
|                        |                  | exposes them as an     |&lt;br /&gt;
|                        |                  | orthogonal vector.     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Pre-DRF NACK (Section 9): receiver-driven nudge exploiting&lt;br /&gt;
    snd_cr.inact &amp;gt; rcv_cr.inact.  Closest analogues are SCTP Gap Ack&lt;br /&gt;
    Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340&lt;br /&gt;
    sec. 11.4) - both let the receiver describe gaps to the sender,&lt;br /&gt;
    but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
  - MAX_RDV window-probe give-up: neither TCP (persist-timer&lt;br /&gt;
    probes until application or R2 abort, RFC 9293 sec. 3.8.6.1)&lt;br /&gt;
    nor QUIC has an explicit FC-give-up counter.  A recursive-&lt;br /&gt;
    network choice: outer layers can drop the flow.&lt;br /&gt;
  - Skip-past-gap reassembly (Section 7.2): SCTP fragments and&lt;br /&gt;
    reassembles every flow regardless of reliability/ordering,&lt;br /&gt;
    using its own per-stream reassembly queue; QUIC fragments via&lt;br /&gt;
    STREAM offsets.  FRCP fragments best-effort flows too, but&lt;br /&gt;
    the receiver drops the broken prefix the moment a later run-&lt;br /&gt;
    start (FIRST or SOLE role) is visible inside the RQ_SIZE-wide&lt;br /&gt;
    reorder ring - no IP-frag-style timeout, no SCTP-style&lt;br /&gt;
    explicit abort.  If no later run-start arrives within the&lt;br /&gt;
    ring, frag_run_inspect returns NOT_READY and the partial run&lt;br /&gt;
    keeps its slots; the next inspect retries.  The trade-off: a&lt;br /&gt;
    permanently-lost MID in a long isolated run holds slots until&lt;br /&gt;
    either a later FIRST/SOLE appears in the ring or the writer&lt;br /&gt;
    stops, at which point the slots are reclaimed on flow&lt;br /&gt;
    teardown.&lt;br /&gt;
  - Reassembly deferred to consume time (Section 7.2), message&lt;br /&gt;
    mode only (qos.service == SVC_MESSAGE): SCTP (RFC 9260&lt;br /&gt;
    sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all&lt;br /&gt;
    hold reassembly state at the receive boundary.  FRCP message-&lt;br /&gt;
    mode leaves fragments in the shared-memory ring until&lt;br /&gt;
    flow_read pulls and lands the SDU directly in the caller&#039;s&lt;br /&gt;
    buffer.  Stream mode (Section 16) uses the standard QUIC-&lt;br /&gt;
    style direct ring placement on receive and does not defer.&lt;br /&gt;
    The optimisation is enabled by the Shared-Memory Subsystem&lt;br /&gt;
    (SSM) packet-buffer ring (see struct ssm_pk_buff at&lt;br /&gt;
    Section 1.1); the analogue is OS-level scatter-gather I/O&lt;br /&gt;
    (recvmsg+iovec), not a transport-layer prior art.&lt;br /&gt;
  - TLP-equivalent tail-loss recovery (RFC 8985 sec. 7;&lt;br /&gt;
    RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss&lt;br /&gt;
    Probe packet, but the same goal is met implicitly by RACK&lt;br /&gt;
    loss detection (Section 8) firing on a non-advancing&lt;br /&gt;
    cumulative ACK once the head-of-line slot ages past the RACK&lt;br /&gt;
    reorder window R = MIN(reo_wnd_mult * min_RTT / 4, SRTT) -&lt;br /&gt;
    well below RTO = max(2 * SRTT, SRTT + (mdev &amp;lt;&amp;lt; MDEV_MUL)).&lt;br /&gt;
    A receiver-driven nudge is also available via the pre-DRF&lt;br /&gt;
    NACK (Section 9).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Slow start, congestion window (cwnd), Additive Increase /&lt;br /&gt;
    Multiplicative Decrease (AIMD), NewReno cwnd inflation.&lt;br /&gt;
    Congestion control lives in the IPCP CA policies and is&lt;br /&gt;
    driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
  - Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC&lt;br /&gt;
    1122 sec. 4.2.3.4).  (Deferred work, not adopted in the&lt;br /&gt;
    current spec.)&lt;br /&gt;
  - TCP Timestamps (RFC 7323) / Protection Against Wrapped&lt;br /&gt;
    Sequences (PAWS) - RTT measurement uses RTTP,&lt;br /&gt;
    not per-segment timestamps.  A peer-supplied timestamp echoed&lt;br /&gt;
    on every ACK lets a malicious peer drive the srtt estimate&lt;br /&gt;
    arbitrarily low, collapsing the RTO and triggering a self-&lt;br /&gt;
    inflicted retransmit storm.  RTTP confines RTT measurement to&lt;br /&gt;
    nonce-authenticated probe round-trips, where a forged echo is&lt;br /&gt;
    rejected before it can reach the estimator.&lt;br /&gt;
  - ECN (Explicit Congestion Notification) response inside FRCP&lt;br /&gt;
    (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
  - IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200&lt;br /&gt;
    sec. 4.5).  Message-mode FRCP relies on the FRCT rq[] reorder&lt;br /&gt;
    ring keyed by seqno (shared by FRTX and best-effort flows) to&lt;br /&gt;
    put fragments back in order; no separate offset field is&lt;br /&gt;
    needed and no IP-style hole-list reassembly buffer is kept.&lt;br /&gt;
    Stream-mode FRCP does carry [start, end) byte offsets&lt;br /&gt;
    (Section 1.5) for direct ring placement on receive.&lt;br /&gt;
  - QUIC STREAM offset+length framing on *every* flow (RFC 9000&lt;br /&gt;
    sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-&lt;br /&gt;
    bit encoding (FFGM/LFGM) and skips the offsets; stream-mode&lt;br /&gt;
    FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with qos.service == SVC_STREAM both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections 6-8.&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension) octets (Sections 1.1&lt;br /&gt;
and 1.5).  Each chunk is one DATA packet with its own seqno and a&lt;br /&gt;
[start, end) byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode FFGM and LFGM are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the [start, end)&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has FIN&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in Section 1.2&lt;br /&gt;
(WR-half close, flow_dealloc, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
[start, end) MUST equal [final-byte, final-byte) (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an snd_fin_sent guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width ring_sz (octets) at the position&lt;br /&gt;
indicated by start, with a two-segment memcpy across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery (Section 6.2) augmented with the packet&#039;s start, end, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s [start, end) front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances lwe and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy `start == the last-delivered slot&#039;s end`; a slot whose&lt;br /&gt;
start does not equal that end is silently dropped at delivery time&lt;br /&gt;
(the seqno is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s end; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding seqno occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
flow_read returns up to count octets from the contiguous prefix&lt;br /&gt;
[next, high-water), where next is the byte the application has&lt;br /&gt;
already consumed up to and high-water is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (next == EOS byte position), flow_read returns&lt;br /&gt;
0 (EOF) - the same shape POSIX read(2) uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-seqno received-bitmap.  Let per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension), the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry (Section 16.1).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(ring_sz) cannot be overrun: the seqno-space rwe is at most&lt;br /&gt;
`rcv_cr.lwe + ring_sz / per_pkt`.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(MAX_STREAM_DATA, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
seqno space.  With one stream per flow there is no MAX_DATA /&lt;br /&gt;
MAX_STREAM_DATA distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time rwe bump with the global non-shrink rule from&lt;br /&gt;
Section 11.&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (start == prior&lt;br /&gt;
end on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when ber == 0 - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
(Section 1.1).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see Section 1.1).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
  - Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
  - Comparable to IPsec ESP transport mode (RFC 4303), which&lt;br /&gt;
    similarly authenticates and encrypts the upper-layer header&lt;br /&gt;
    plus payload, and to QUIC packet protection (RFC 9001 sec. 5),&lt;br /&gt;
    with the difference that QUIC must leave the destination&lt;br /&gt;
    connection ID in the clear for routing whereas FRCP relies on&lt;br /&gt;
    the IPCP below for delivery and can therefore encrypt its&lt;br /&gt;
    entire PCI.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keying granularity.  FRCP runs key exchange (kex) per flow, so&lt;br /&gt;
each flow_alloc yields independent symmetric keys.  This is&lt;br /&gt;
finer-grained than QUIC (per-connection, RFC 9001, where one&lt;br /&gt;
handshake covers all multiplexed streams) and finer-grained than&lt;br /&gt;
typical IPsec deployment (per-host-pair Security Associations,&lt;br /&gt;
SAs).  Forward secrecy follows from the kex when an ephemeral&lt;br /&gt;
Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH +&lt;br /&gt;
post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection.  The AEAD layer itself does NOT carry an&lt;br /&gt;
explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec.&lt;br /&gt;
3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the&lt;br /&gt;
seqno-space duplicate-suppression in Section 6.2 rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates&lt;br /&gt;
the seqno and a replay re-presents an old seqno that is then&lt;br /&gt;
discarded either as a duplicate (still inside the receive window)&lt;br /&gt;
or as outside the receive window, depending on how far lwe has&lt;br /&gt;
advanced since the original packet was delivered.  RAW&lt;br /&gt;
(qos.service == SVC_RAW) flows have no FRCP layer and therefore&lt;br /&gt;
no replay protection at the AEAD layer either; deployments that&lt;br /&gt;
need replay rejection on RAW flows MUST provide it at a higher&lt;br /&gt;
layer.&lt;br /&gt;
&lt;br /&gt;
Layering.  The AEAD wrap sits below FRCP on the data path, so&lt;br /&gt;
RAW best-effort flows (qos.service == SVC_RAW, the UDP-equivalent&lt;br /&gt;
service of Section 2.2) inherit the same per-flow integrity +&lt;br /&gt;
confidentiality scope as FRCP-engaged flows - whatever the IPCP&lt;br /&gt;
and FRCP (if any) put on the wire is what the AEAD authenticates.&lt;br /&gt;
No DTLS-equivalent layering is required for confidentiality and&lt;br /&gt;
integrity; replay protection above AEAD is a separate concern as&lt;br /&gt;
noted above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 791]   J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791,&lt;br /&gt;
              September 1981.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 793]   J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7,&lt;br /&gt;
              RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 813]   D. D. Clark, &amp;quot;Window and Acknowledgement Strategy&lt;br /&gt;
              in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 896]   J. Nagle, &amp;quot;Congestion Control in IP/TCP&lt;br /&gt;
              Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 1122]  R. Braden (ed.), &amp;quot;Requirements for Internet Hosts&lt;br /&gt;
              -- Communication Layers&amp;quot;, STD 3, RFC 1122,&lt;br /&gt;
              October 1989.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2018]  M. Mathis, J. Mahdavi, S. Floyd, A. Romanow,&lt;br /&gt;
              &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018,&lt;br /&gt;
              October 1996.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2119]  S. Bradner, &amp;quot;Key words for use in RFCs to Indicate&lt;br /&gt;
              Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2883]  S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky,&lt;br /&gt;
              &amp;quot;An Extension to the Selective Acknowledgement&lt;br /&gt;
              (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 3758]  R. Stewart, M. Ramalho, Q. Xie, M. Tuexen,&lt;br /&gt;
              P. Conrad, &amp;quot;Stream Control Transmission Protocol&lt;br /&gt;
              (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758,&lt;br /&gt;
              May 2004.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 3828]  L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson&lt;br /&gt;
              (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User&lt;br /&gt;
              Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828,&lt;br /&gt;
              July 2004.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 4303]  S. Kent, &amp;quot;IP Encapsulating Security Payload&lt;br /&gt;
              (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 4340]  E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram&lt;br /&gt;
              Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340,&lt;br /&gt;
              March 2006.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5288]  J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois&lt;br /&gt;
              Counter Mode (GCM) Cipher Suites for TLS&amp;quot;,&lt;br /&gt;
              RFC 5288, August 2008.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5595]  G. Fairhurst, &amp;quot;The Datagram Congestion Control&lt;br /&gt;
              Protocol (DCCP) Service Codes&amp;quot;, RFC 5595,&lt;br /&gt;
              September 2009.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5681]  M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion&lt;br /&gt;
              Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5925]  J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP&lt;br /&gt;
              Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5961]  A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving&lt;br /&gt;
              TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;,&lt;br /&gt;
              RFC 5961, August 2010.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6298]  V. Paxson, M. Allman, J. Chu, M. Sargent,&lt;br /&gt;
              &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298,&lt;br /&gt;
              June 2011.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6528]  F. Gont, S. Bellovin, &amp;quot;Defending against Sequence&lt;br /&gt;
              Number Attacks&amp;quot;, RFC 6528, February 2012.&lt;br /&gt;
              Obsoletes RFC 1948.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6582]  T. Henderson, S. Floyd, A. Gurtov, Y. Nishida,&lt;br /&gt;
              &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery&lt;br /&gt;
              Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 7323]  D. Borman, B. Braden, V. Jacobson,&lt;br /&gt;
              R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High&lt;br /&gt;
              Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 7675]  M. Perumal, D. Wing, R. Ravindranath, T. Reddy,&lt;br /&gt;
              M. Thomson, &amp;quot;Session Traversal Utilities for NAT&lt;br /&gt;
              (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675,&lt;br /&gt;
              October 2015.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8174]  B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in&lt;br /&gt;
              RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8200]  S. Deering, R. Hinden, &amp;quot;Internet Protocol,&lt;br /&gt;
              Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200,&lt;br /&gt;
              July 2017.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8439]  Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF&lt;br /&gt;
              Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8446]  E. Rescorla, &amp;quot;The Transport Layer Security (TLS)&lt;br /&gt;
              Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8985]  Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha,&lt;br /&gt;
              &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;,&lt;br /&gt;
              RFC 8985, February 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9000]  J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A&lt;br /&gt;
              UDP-Based Multiplexed and Secure Transport&amp;quot;,&lt;br /&gt;
              RFC 9000, May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9001]  M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to&lt;br /&gt;
              Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9002]  J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss&lt;br /&gt;
              Detection and Congestion Control&amp;quot;, RFC 9002,&lt;br /&gt;
              May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9147]  E. Rescorla, H. Tschofenig, N. Modadugu,&lt;br /&gt;
              &amp;quot;The Datagram Transport Layer Security (DTLS)&lt;br /&gt;
              Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9260]  R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control&lt;br /&gt;
              Transmission Protocol&amp;quot;, RFC 9260, June 2022.&lt;br /&gt;
              Obsoletes RFC 4960.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9293]  W. Eddy (ed.), &amp;quot;Transmission Control Protocol&lt;br /&gt;
              (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes&lt;br /&gt;
              RFC 793 and several follow-ons; updates RFC 1122&lt;br /&gt;
              and others.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - J. Day, &amp;quot;Patterns in Network Architecture: A Return to&lt;br /&gt;
    Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative&lt;br /&gt;
    to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates&lt;br /&gt;
    in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport&lt;br /&gt;
    Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5,&lt;br /&gt;
    1981.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - tcp_rtt_estimator() in net/ipv4/tcp_input.c of the Linux&lt;br /&gt;
    kernel, defining the asymmetric mdev variance update used as&lt;br /&gt;
    FRCP&#039;s default RTT estimator (Section 12).  Line-stable&lt;br /&gt;
    browseable copy at&lt;br /&gt;
    https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1911</id>
		<title>Flow and Retransmission Control Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Flow_and_Retransmission_Control_Protocol&amp;diff=1911"/>
		<updated>2026-05-17T13:50:31Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= FRCP - Flow and Retransmission Control Protocol =&lt;br /&gt;
&lt;br /&gt;
FRCP runs end-to-end between two peers over a flow.  It delivers&lt;br /&gt;
reliability, in-order delivery, flow control, and liveness.&lt;br /&gt;
Congestion Control (CC) is not in FRCP - that lives in the IPC&lt;br /&gt;
Process (IPCP) Congestion Avoidance (CA) policies, orthogonal to&lt;br /&gt;
FRCP.  Flow allocation, naming, and IPCP lifecycle are handled by&lt;br /&gt;
the IPC Resource Manager daemon (IRMd).&lt;br /&gt;
&lt;br /&gt;
FRCT (Flow and Retransmission Control Task) is the libouroboros&lt;br /&gt;
implementation of FRCP; the task lives in src/lib/frct.c.  The&lt;br /&gt;
remainder of this document describes the FRCP wire protocol and the&lt;br /&gt;
behaviour FRCT realises.  Code symbols retain the FRCT_ prefix&lt;br /&gt;
(FRCT_DATA, FRCT_RXM, ...) because they belong to the implementing&lt;br /&gt;
task; this document references them verbatim.&lt;br /&gt;
&lt;br /&gt;
The keywords &amp;quot;MUST&amp;quot;, &amp;quot;MUST NOT&amp;quot;, &amp;quot;REQUIRED&amp;quot;, &amp;quot;SHALL&amp;quot;, &amp;quot;SHALL NOT&amp;quot;,&lt;br /&gt;
&amp;quot;SHOULD&amp;quot;, &amp;quot;SHOULD NOT&amp;quot;, &amp;quot;RECOMMENDED&amp;quot;, &amp;quot;MAY&amp;quot;, and &amp;quot;OPTIONAL&amp;quot; in&lt;br /&gt;
this document are to be interpreted as described in BCP 14 (Best&lt;br /&gt;
Current Practice; RFC 2119, RFC 8174) when, and only when, they&lt;br /&gt;
appear in all capitals.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notation ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  u32, u8       Unsigned 32-bit / 8-bit integers (kernel-C style).&lt;br /&gt;
  ns            Nanoseconds.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Modular sequence-number comparators (32-bit, modulo 2^32):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    before(a, b)  ==  (int32_t)(a - b) &amp;lt; 0&lt;br /&gt;
    after(a, b)   ==  before(b, a)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Used throughout for ackno / seqno ordering checks.&lt;br /&gt;
&lt;br /&gt;
Round-Trip Time (RTT) abbreviations used throughout:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    SRTT          Smoothed RTT estimate (RFC 6298).&lt;br /&gt;
    mdev          Mean deviation of RTT (Linux variance estimator).&lt;br /&gt;
    EWMA          Exponentially Weighted Moving Average.&lt;br /&gt;
    RTO           Retransmission Timeout, max(RTO_MIN,&lt;br /&gt;
                  srtt + (mdev &amp;lt;&amp;lt; MDEV_MUL)).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Timer-bound symbols t_a (a-timer, ACK delay) and t_r (r-timer,&lt;br /&gt;
retransmission window) are defined in Section 8; t_mpl (Maximum&lt;br /&gt;
Packet Lifetime) is introduced in Section 2.1 (the inact field)&lt;br /&gt;
with heritage in Section 15.&lt;br /&gt;
&lt;br /&gt;
Wire-format diagrams follow the IETF convention: bit 0 is the&lt;br /&gt;
leftmost (most significant) bit and fields are in network byte&lt;br /&gt;
order unless stated otherwise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Table of Contents ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. Wire format&lt;br /&gt;
     1.1. PCI header&lt;br /&gt;
     1.2. Flag bits&lt;br /&gt;
     1.3. SACK payload&lt;br /&gt;
     1.4. RTTP payload&lt;br /&gt;
     1.5. Stream PCI extension&lt;br /&gt;
  2. Per-flow state and service modes&lt;br /&gt;
     2.1. Per-flow state&lt;br /&gt;
     2.2. Service modes (orthogonal axes)&lt;br /&gt;
  3. Protocol parameters&lt;br /&gt;
  4. Sequence-number rotation (DRF)&lt;br /&gt;
  5. Send path&lt;br /&gt;
  6. Receive path&lt;br /&gt;
     6.1. Early-exit dispatch&lt;br /&gt;
     6.2. Locked main path&lt;br /&gt;
  7. Read path and reassembly&lt;br /&gt;
     7.1. Read path&lt;br /&gt;
     7.2. Fragmentation and reassembly&lt;br /&gt;
  8. Retransmission&lt;br /&gt;
  9. Pre-DRF NACK&lt;br /&gt;
 10. Cumulative + selective ACK&lt;br /&gt;
 11. Flow control&lt;br /&gt;
 12. RTT estimation&lt;br /&gt;
 13. Liveness (keepalive)&lt;br /&gt;
 14. Linger / teardown&lt;br /&gt;
 15. Heritage and adopted techniques&lt;br /&gt;
     15.1. Original to FRCP (no clean prior art)&lt;br /&gt;
     15.2. Not adopted&lt;br /&gt;
 16. Stream-mode flows&lt;br /&gt;
     16.1. Send&lt;br /&gt;
     16.2. Receive&lt;br /&gt;
     16.3. Read&lt;br /&gt;
     16.4. Flow control&lt;br /&gt;
     16.5. Security considerations&lt;br /&gt;
 17. References&lt;br /&gt;
     17.1. IETF documents&lt;br /&gt;
     17.2. Books and journal papers&lt;br /&gt;
     17.3. Source-code references&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1. Wire format ==&lt;br /&gt;
&lt;br /&gt;
=== 1.1. PCI header ===&lt;br /&gt;
&lt;br /&gt;
Fixed 16-octet base Protocol-Control Information (PCI) header&lt;br /&gt;
prefixed to every FRCP packet (RFC convention: bit 0 leftmost,&lt;br /&gt;
most-significant bit first).  All multi-byte fields except hcs&lt;br /&gt;
are in network byte order; hcs is an opaque 16-bit value that&lt;br /&gt;
the receiver recomputes from the wire bytes and compares to the&lt;br /&gt;
in-place pci-&amp;gt;hcs read, so its on-wire byte order need only&lt;br /&gt;
match between peers running compatible builds.  DATA packets on&lt;br /&gt;
stream-mode flows carry an additional 8-octet extension (see&lt;br /&gt;
Section 1.5); SACK and RTTP carry their own payloads after the&lt;br /&gt;
base PCI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |             flags             |              hcs              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            window                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            seqno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            ackno                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                     payload (variable) ...&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  flags   - feature/type bitmap (see 1.2).&lt;br /&gt;
  hcs     - CRC-16-CCITT-FALSE Header Check Sequence (HCS) over&lt;br /&gt;
            flags + window + seqno + ackno (+ stream extension when&lt;br /&gt;
            present); the two octets of the hcs field itself are&lt;br /&gt;
            omitted from the CRC input.  Verified on receive before&lt;br /&gt;
            any flag-driven dispatch.&lt;br /&gt;
  window  - receiver-advertised right window edge (valid iff FC).&lt;br /&gt;
  seqno   - per-flow sequence number.&lt;br /&gt;
  ackno   - cumulative Acknowledgement (ACK) (valid iff ACK).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A single packet can simultaneously carry DATA + ACK + FC (Flow&lt;br /&gt;
Control) + RXM (Retransmission) by ORing flag bits; the PCI&lt;br /&gt;
multiplexes control on the same wire frame in the spirit of SCTP&lt;br /&gt;
chunk bundling (RFC 9260 sec. 6.10) and QUIC frame multiplexing&lt;br /&gt;
(RFC 9000 sec. 12.4).  DATA-bearing packets carry the caller&#039;s&lt;br /&gt;
payload after the PCI; SACK (Selective Acknowledgement) and RTTP&lt;br /&gt;
(Round-Trip Time Probe) carry their own typed payloads after the&lt;br /&gt;
PCI.&lt;br /&gt;
&lt;br /&gt;
Optional framing (per-flow, see Section 2.2).  On the wire, the&lt;br /&gt;
order from inside out is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    [   PCI + body          ]    -- the FRCP packet&lt;br /&gt;
    [   PCI + body + CRC-32 ]    -- CRC-32 covers the body only (PCI&lt;br /&gt;
                                    is in HCS); appended iff qs.ber&lt;br /&gt;
                                    == 0 on DATA, or on every SACK&lt;br /&gt;
                                    packet&lt;br /&gt;
    [ AEAD-wrap of above    ]    -- iff Authenticated Encryption&lt;br /&gt;
                                    with Associated Data (AEAD) is&lt;br /&gt;
                                    enabled&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - HCS in the PCI covers the header fields on every packet and is&lt;br /&gt;
    verified before any flag-driven dispatch.&lt;br /&gt;
  - The CRC-32 trailer (IEEE 802.3 / zlib reflected polynomial&lt;br /&gt;
    0xEDB88320, init 0xFFFFFFFF, xor-out 0xFFFFFFFF) covers the&lt;br /&gt;
    body on DATA when qs.ber == 0 and on every SACK packet; the&lt;br /&gt;
    trailer is written as a raw uint32_t (the same convention as&lt;br /&gt;
    hcs: opaque on the wire as long as both peers run compatible&lt;br /&gt;
    builds).  The PCI is not under the CRC (Cyclic Redundancy&lt;br /&gt;
    Check) because the HCS already protects it.  It is&lt;br /&gt;
    appended before AEAD encryption and therefore rides inside the&lt;br /&gt;
    AEAD wrap when both are active; the AEAD tag (~2^-128 forgery&lt;br /&gt;
    probability) dominates the CRC (~2^-32) for integrity in that&lt;br /&gt;
    mode but the CRC trailer is currently retained.&lt;br /&gt;
  - When encryption is enabled, the entire (possibly-CRC&#039;d) FRCP&lt;br /&gt;
    packet is wrapped with AEAD inside the shared-memory packet&lt;br /&gt;
    buffer (spb, struct ssm_pk_buff); the packet grows by the AEAD&lt;br /&gt;
    overhead, namely a leading nonce / Initialization Vector (IV)&lt;br /&gt;
    of headsz bytes (crypt_get_ivsz) and a trailing authentication&lt;br /&gt;
    tag of tailsz bytes (crypt_get_tagsz).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both CRC and AEAD are layered around the FRCP wire format and&lt;br /&gt;
are not visible to the FRCP machinery itself.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.2. Flag bits ===&lt;br /&gt;
&lt;br /&gt;
Flag bits are numbered most-significant-bit first to match the wire&lt;br /&gt;
diagram (bit numbering per Section 1.1; bit 0 is the MSB of the&lt;br /&gt;
16-bit flags field and lands at wire-position 0 in network byte&lt;br /&gt;
order).  Bits 13..15 are reserved and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
    | Bit  | Mask   | Name   | Meaning                                |&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
    |   0  | 0x8000 | DATA   | Carries caller payload                 |&lt;br /&gt;
    |   1  | 0x4000 | DRF    | Data Run Flag: start of a fresh run    |&lt;br /&gt;
    |   2  | 0x2000 | ACK    | Acknowledgement: ackno field valid     |&lt;br /&gt;
    |   3  | 0x1000 | NACK   | Negative ACK; seqno = arrival_seqno-1  |&lt;br /&gt;
    |   4  | 0x0800 | FC     | Flow Control: window field valid (rwe) |&lt;br /&gt;
    |   5  | 0x0400 | RDVS   | Rendezvous probe (window-closed)       |&lt;br /&gt;
    |   6  | 0x0200 | FFGM   | First Fragment (role bit 0; see below) |&lt;br /&gt;
    |   7  | 0x0100 | LFGM   | Last Fragment (role bit 1; see below)  |&lt;br /&gt;
    |   8  | 0x0080 | RXM    | Retransmission                         |&lt;br /&gt;
    |   9  | 0x0040 | SACK   | Selective ACK block list in payload    |&lt;br /&gt;
    |  10  | 0x0020 | RTTP   | RTT Probe / echo (payload follows)     |&lt;br /&gt;
    |  11  | 0x0010 | KA     | Keepalive                              |&lt;br /&gt;
    |  12  | 0x0008 | FIN    | End-of-stream marker (stream mode)     |&lt;br /&gt;
    | 13-15|   --   |  --    | Reserved (MUST be zero)                |&lt;br /&gt;
    +------+--------+--------+----------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The (FFGM, LFGM) pair encodes the fragment role of a DATA-bearing&lt;br /&gt;
Service Data Unit (SDU), SCTP-style begin/end flags (RFC 9260&lt;br /&gt;
sec. 3.3.1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
    | FFGM LFGM | Role                                            |&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
    |   1   1   | Sole / un-fragmented SDU (begin AND end)        |&lt;br /&gt;
    |   1   0   | First fragment of a multi-fragment SDU          |&lt;br /&gt;
    |   0   0   | Middle fragment                                 |&lt;br /&gt;
    |   0   1   | Last fragment                                   |&lt;br /&gt;
    +-----------+-------------------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each fragment is carried in its own FRCP packet with its own seqno;&lt;br /&gt;
FRTX (the FRCT Retransmission service mode, see Section 2.2)&lt;br /&gt;
recovers individual fragments via the normal Retransmission Timeout&lt;br /&gt;
(RTO) / SACK / Recent Acknowledgement (RACK, RFC 8985) path.  The&lt;br /&gt;
receiver reassembles the SDU at consume time once the contiguous&lt;br /&gt;
[FIRST .. LAST] run has fully arrived.  On non-DATA packets the role&lt;br /&gt;
bits are unused and MUST be transmitted as zero.&lt;br /&gt;
&lt;br /&gt;
In stream mode (qos.service == SVC_STREAM, see Section 16) there are&lt;br /&gt;
no SDU boundaries to encode, so FFGM and LFGM are unused and MUST&lt;br /&gt;
be transmitted as zero.  End-of-stream uses a dedicated bit (FIN,&lt;br /&gt;
bit 12) carried on a 0-byte DATA packet, emitted at write-half close&lt;br /&gt;
(fccntl to FLOWFRDONLY), during linger drain, and at flow_dealloc;&lt;br /&gt;
emission is idempotent (first call wins).  After contiguous delivery&lt;br /&gt;
of the FIN-bearing slot, the receiver latches byte_fin at the FIN&#039;s&lt;br /&gt;
start offset; flow_read returns 0 (end-of-file, EOF) once buffered&lt;br /&gt;
bytes have been drained up to byte_fin.  Per-byte position is&lt;br /&gt;
carried by the [start, end) extension (Section 1.5).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.3. SACK payload ===&lt;br /&gt;
&lt;br /&gt;
A SACK packet has the FRCT_ACK | FRCT_FC | FRCT_SACK flag bits set&lt;br /&gt;
(bit numbering per Section 1.1).  Following the 16-octet PCI, the&lt;br /&gt;
payload is a 2-octet block count (network byte order), 2 octets of&lt;br /&gt;
padding to 4-byte align the block list, then n_blocks pairs of&lt;br /&gt;
32-bit start/end seqnos describing *present* (received) ranges&lt;br /&gt;
above the cumulative ACK.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |           n_blocks            |        padding (2 octets)     |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[0]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            end[0]                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                           start[1]                            |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
                       ... n_blocks pairs total ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
n_blocks &amp;lt;= SACK_MAX_BLOCKS (2048).  The per-flow effective cap is&lt;br /&gt;
further bounded by (frag_mtu - PCI - 4) / 8 blocks per packet; SACK&lt;br /&gt;
packets carry no stream extension, so PCI here is the 16-octet base&lt;br /&gt;
header even on stream-mode flows.&lt;br /&gt;
&lt;br /&gt;
Wire invariant: every block produced by the receiver, except an&lt;br /&gt;
optional leading Duplicate SACK (D-SACK) block as described below,&lt;br /&gt;
describes a range strictly above the cumulative ACK carried in the&lt;br /&gt;
PCI ackno field (after(start[i], ackno)).  This makes the D-SACK&lt;br /&gt;
convention below unambiguous; the receiver-side builder MUST&lt;br /&gt;
preserve it.&lt;br /&gt;
&lt;br /&gt;
Duplicate SACK (D-SACK, RFC 2883) is signalled in-band: no flag&lt;br /&gt;
bit, no extra framing.  Modular seqno arithmetic uses the&lt;br /&gt;
before() / after() comparators defined in the Notation block.&lt;br /&gt;
Block[0] carries a D-SACK report when either:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  case 1 (RFC 2883 sec. 4.1.1, full duplicate):&lt;br /&gt;
      before(blocks[0].start, ackno) and ackno - blocks[0].start is&lt;br /&gt;
      within MAX_DSACK_LAG (== RQ_SIZE).  A single duplicate seqno&lt;br /&gt;
      observed below the cumulative ACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  case 2 (RFC 2883 sec. 4.1.2, partial duplicate):&lt;br /&gt;
      blocks[0] is a sub-range of some blocks[i&amp;gt;0] (not exactly&lt;br /&gt;
      equal).  Reports a duplicate of an in-window seqno that the&lt;br /&gt;
      same packet&#039;s remaining SACK blocks already describe as&lt;br /&gt;
      received.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Senders that do not implement D-SACK process block[0] through the&lt;br /&gt;
normal SACK-mark loop and the existing clamp-and-skip path makes&lt;br /&gt;
case-1 a no-op (start &amp;lt; snd_cr.lwe clamps to snd_cr.lwe, the inner&lt;br /&gt;
loop then skips k == snd_cr.lwe) and case-2 idempotent (same slots&lt;br /&gt;
NULL&#039;d twice).  D-SACK-aware senders feed the report into the RACK&lt;br /&gt;
reo_wnd_mult scaler (RFC 8985 sec. 6.2 step 4): bump on receipt&lt;br /&gt;
(cap 20), halve once per 16 cumulatively-ACK&#039;d seqnos since the&lt;br /&gt;
most recent D-SACK arrival or halve event, reset to 1 on an RTO&lt;br /&gt;
timer fire at the head-of-line.  D-SACK alone never enters&lt;br /&gt;
NewReno-careful recovery (see Section 8); only non-D-SACK blocks&lt;br /&gt;
count as gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.4. RTTP payload ===&lt;br /&gt;
&lt;br /&gt;
An RTTP (Round-Trip Time Probe) packet has only the FRCT_RTTP flag&lt;br /&gt;
set (bit numbering per Section 1.1).  Following the 16-octet PCI,&lt;br /&gt;
the payload is 24 octets (packed):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          probe_id                             |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                          echo_id                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +                  nonce (16 octets, echoed verbatim)           +&lt;br /&gt;
    |                                                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  probe_id - sender counter, 0 on reply, 0 reserved.&lt;br /&gt;
  echo_id  - peer&#039;s probe_id, 0 on outbound probe.&lt;br /&gt;
  nonce    - random, echoed unmodified, memcmp&#039;d to defeat spoof.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 1.5. Stream PCI extension ===&lt;br /&gt;
&lt;br /&gt;
A stream-mode flow (qos.service == SVC_STREAM) carries an extra&lt;br /&gt;
8-octet extension after the 16-octet base PCI on every DATA packet&lt;br /&gt;
(bit numbering per Section 1.1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     0                   1                   2                   3&lt;br /&gt;
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                            start                              |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
    |                             end                               |&lt;br /&gt;
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  start - octet offset of the first payload byte in the stream.&lt;br /&gt;
  end   - octet offset one past the last payload byte;&lt;br /&gt;
          end - start equals the on-wire payload length.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Total stream-mode PCI for DATA packets is 24 octets (16 base + 8&lt;br /&gt;
extension); control packets (SACK, RTTP, bare ACK, KA, etc.) retain&lt;br /&gt;
the 16-octet base PCI.  Stream mode MUST be negotiated at flow&lt;br /&gt;
allocation; the extension is present iff stream mode is in use,&lt;br /&gt;
never on a per-packet basis.  Both peers MUST treat start/end as&lt;br /&gt;
monotonic 32-bit byte offsets; when a slot reaches the head of the&lt;br /&gt;
contiguous run with start not equal to the prior packet&#039;s end the&lt;br /&gt;
slot is silently dropped at delivery time (Section 16) rather&lt;br /&gt;
than rejected at stash.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC STREAM-frame reassembly model (RFC 9000 sec. 19.8):&lt;br /&gt;
each packet carries its packet seqno (this PCI&#039;s seqno field) and a&lt;br /&gt;
separate stream byte position (start/end).  Separating the two&lt;br /&gt;
avoids TCP&#039;s conflation of packet identity with byte position which&lt;br /&gt;
forces Karn&#039;s algorithm for Round-Trip Time (RTT) sampling (no RTT&lt;br /&gt;
sample on retransmits, RFC 6298 sec. 3); FRCP applies the&lt;br /&gt;
Karn-equivalent gate via a combination of per-packet FRCT_RXM,&lt;br /&gt;
per-slot SND_RTX flags, and a sample-fence rtt_lwe (see Section 2.1&lt;br /&gt;
and Section 12).  FRCP&#039;s fixed-32-bit start/end wrap at 4 GiB of&lt;br /&gt;
wire bytes, narrower than QUIC&#039;s 62-bit varint offset (cf. RFC 9000&lt;br /&gt;
sec. 16); the on-wire wrap is handled by the same modular before()&lt;br /&gt;
/ after() comparators (Section 1.3) FRCP uses for seqnos, which&lt;br /&gt;
remain unambiguous as long as the in-flight byte window stays&lt;br /&gt;
strictly under 2 GiB (the half-range of the signed-int32 difference&lt;br /&gt;
in before()).  The default per-flow ring is 1 MiB; the&lt;br /&gt;
implementation caps ring_sz at 128 MiB (FRCT_STREAM_RING_SZ_MAX),&lt;br /&gt;
well below the 2 GiB half-range bound.  The runtime byte counters&lt;br /&gt;
exposed via FUSE (Filesystem in Userspace) in the Ouroboros&lt;br /&gt;
Resource Information Base (RIB, a virtual-filesystem introspection&lt;br /&gt;
bridge) are platform size_t and do not wrap on 64-bit hosts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Per-flow state and service modes ==&lt;br /&gt;
&lt;br /&gt;
=== 2.1. Per-flow state ===&lt;br /&gt;
&lt;br /&gt;
Each flow keeps a sender control record and a receiver control&lt;br /&gt;
record:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    lwe    : u32  snd: oldest unacked seqno (cumulative ACK&lt;br /&gt;
                  boundary as seen by sender);&lt;br /&gt;
                  rcv: next in-order seqno expected&lt;br /&gt;
    rwe    : u32  snd: peer-advertised right window edge;&lt;br /&gt;
                  rcv: locally-advertised right window edge&lt;br /&gt;
    cflags : u8   per-direction feature flags: retransmission&lt;br /&gt;
                  (FRCTFRTX), receiver flow control&lt;br /&gt;
                  (FRCTFRESCNTL), linger-on-close (FRCTFLINGER);&lt;br /&gt;
                  see &amp;lt;ouroboros/fccntl.h&amp;gt;&lt;br /&gt;
    seqno  : u32  snd: next seqno to send;&lt;br /&gt;
                  rcv: force-ACK trigger - set on a stale or dup&lt;br /&gt;
                  DATA so the next ack_snd emits a fresh&lt;br /&gt;
                  cumulative ACK&lt;br /&gt;
    ackno  : u32  snd: outbound ACK-packet seqno counter,&lt;br /&gt;
                  incremented for every ACK-bearing packet (bare&lt;br /&gt;
                  ACK, delayed ACK, SACK); used by wire-dup ACK&lt;br /&gt;
                  detection;&lt;br /&gt;
                  rcv: incoming-ACK dedup tracker&lt;br /&gt;
    act    : ns   last activity (used by inactivity / DRF)&lt;br /&gt;
    inact  : ns   inactivity threshold; sender = 3*mpl + a + r + 1s,&lt;br /&gt;
                  receiver = 2*mpl + a + r + 1s.  mpl is the&lt;br /&gt;
                  Maximum Packet Lifetime (delta-t terminology;&lt;br /&gt;
                  see Section 15); a and r are the FRCT a-timer&lt;br /&gt;
                  and r-timer bounds (see Section 8).  The&lt;br /&gt;
                  asymmetry is load-bearing for pre-DRF NACK&lt;br /&gt;
                  (Section 9).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sender holds a per-slot ring snd_slots[RQ_SIZE] keyed by&lt;br /&gt;
(seqno mod RQ_SIZE).  Each slot tracks its retransmit entry (rxm),&lt;br /&gt;
last-send timestamp, and retransmit flag bits: SND_RTX (a&lt;br /&gt;
retransmit is pending or has fired, gates the next RTT sample&lt;br /&gt;
under Karn) and SND_FAST_RXM (one-shot fast-retransmit staged for&lt;br /&gt;
this loss event).&lt;br /&gt;
&lt;br /&gt;
The receiver holds a parallel reorder ring rcv_slots[RQ_SIZE]&lt;br /&gt;
(referred to as rq[] in prose) holding stashed out-of-order&lt;br /&gt;
packet-buffer indexes; both FRTX and best-effort flows share this&lt;br /&gt;
path.  The invariant rwe - lwe &amp;lt;= RQ_SIZE holds: on each consume&lt;br /&gt;
the receiver advances rwe by the consumed count, capping the&lt;br /&gt;
receive window at RQ_SIZE seqno slots.&lt;br /&gt;
&lt;br /&gt;
A separate fence variable rtt_lwe is bumped on every retransmit&lt;br /&gt;
(timer-fire, SACK-driven, fast-rxm, NACK-driven) and on every&lt;br /&gt;
seqno_rotate (Section 4) to mark the seqno range whose RTT samples&lt;br /&gt;
MUST be discarded.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2.2. Service modes (orthogonal axes) ===&lt;br /&gt;
&lt;br /&gt;
FRCP exposes its wire features as a vector of independent QoS&lt;br /&gt;
axes selected at flow allocation time.  All flows go through the&lt;br /&gt;
same flow_alloc(name, qos, ...) primitive; the qosspec_t passed&lt;br /&gt;
in determines which protocol machinery engages on the wire.  This&lt;br /&gt;
contrasts with the POSIX BSD socket model where TCP and UDP&lt;br /&gt;
require different socket types (SOCK_STREAM / SOCK_DGRAM).&lt;br /&gt;
&lt;br /&gt;
The axes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  service   0 = unordered (no FRCP engagement: raw datagrams,&lt;br /&gt;
              no PCI on the wire, UDP-equivalent at this layer)&lt;br /&gt;
            1 = message-ordered (FRCP engaged; SDU boundaries&lt;br /&gt;
              preserved across fragmentation)&lt;br /&gt;
            2 = stream (byte-oriented, no SDU boundaries; FRTX&lt;br /&gt;
              required)&lt;br /&gt;
  loss      0 = lossless service requested: FRTX retransmit&lt;br /&gt;
              machinery engages (Section 8); MUST be 0 for&lt;br /&gt;
              service=2.  Non-zero = best-effort, FRTX off.&lt;br /&gt;
  ber       Bit Error Rate tolerance.&lt;br /&gt;
            0 = error-free service requested: a CRC trailer is&lt;br /&gt;
              appended after the body of DATA packets and verified&lt;br /&gt;
              on receive (added / checked outside the FRCP PCI;&lt;br /&gt;
              see Section 1.1).  Non-zero = peer accepts errors;&lt;br /&gt;
              trailer omitted.  SACK control packets carry a&lt;br /&gt;
              CRC32 trailer regardless of ber; the ber gate&lt;br /&gt;
              applies to DATA only.&lt;br /&gt;
  timeout   Peer-timeout (ms); 0 disables the keepalive timer.&lt;br /&gt;
              Independent of FRCP engagement.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Encryption is a separate per-flow attribute set at flow setup;&lt;br /&gt;
when enabled it wraps the FRCP packet (PCI + body, plus the CRC&lt;br /&gt;
trailer if any) under AEAD, expanding the spb by headsz + tailsz&lt;br /&gt;
octets (nonce / tag).  The CRC trailer is currently kept inside&lt;br /&gt;
the AEAD wrap (see Section 1.1).&lt;br /&gt;
&lt;br /&gt;
Reachable combinations exported by include/ouroboros/qos.h:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
  | Cube            | service | loss | ber | Engaged               |&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
  | qos_raw         |    0    |   1  |   1 | Raw passthrough       |&lt;br /&gt;
  | qos_raw_safe    |    0    |   1  |   0 | Raw + CRC trailer     |&lt;br /&gt;
  | qos_rt          |    1    |   1  |   1 | FRCP, no FRTX, no CRC |&lt;br /&gt;
  | qos_rt_safe     |    1    |   1  |   0 | FRCP, no FRTX, CRC    |&lt;br /&gt;
  | qos_msg         |    1    |   0  |   0 | FRCP + FRTX           |&lt;br /&gt;
  | qos_stream      |    2    |   0  |   0 | FRCP + FRTX, stream   |&lt;br /&gt;
  +-----------------+---------+------+-----+-----------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Forced couplings actually enforced by the public API:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - service == SVC_STREAM (2) requires loss == 0; flow_alloc /&lt;br /&gt;
    flow_accept reject the pair otherwise with -EINVAL.&lt;br /&gt;
  - FRTX requires FRCP engagement (service != SVC_RAW); requesting&lt;br /&gt;
    loss = 0 with service = SVC_RAW is structurally a no-op&lt;br /&gt;
    because no frcti is created.&lt;br /&gt;
  - The QOS_DISABLE_CRC build flag globally forces ber = 1.&lt;br /&gt;
    Note: this flag defaults to ON, so default builds ship with&lt;br /&gt;
    CRC disabled until QOS_DISABLE_CRC is set to OFF.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Caveat: the API does NOT force ber = 0 when service != SVC_RAW.&lt;br /&gt;
qos_rt has service = SVC_MESSAGE with ber = 1, which means the PCI&lt;br /&gt;
itself is not CRC-protected on that cube; the HCS (Section 1.1)&lt;br /&gt;
remains the only integrity check on the header.&lt;br /&gt;
&lt;br /&gt;
The FRCP-no-FRTX regime (service = SVC_MESSAGE, loss &amp;gt; 0) is meaningful&lt;br /&gt;
and live: sequence numbering, in-order delivery, flow-control&lt;br /&gt;
advertisement, KA, DRF rotation, and SDU fragmentation /&lt;br /&gt;
reassembly (Section 7.2) all run.  Lost packets are dropped&lt;br /&gt;
rather than retransmitted; a permanently-lost mid-fragment is&lt;br /&gt;
dropped via skip-past-gap once a later SDU is visible in the&lt;br /&gt;
reorder ring.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3. Protocol parameters ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
    | Parameter          | Value                  | Role              |&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
    | RQ_SIZE            | compile-time, power of | Slot ring / rcv   |&lt;br /&gt;
    |                    |  2 (default 128)       | window width      |&lt;br /&gt;
    | START_WINDOW       | compile-time, power of | Initial rwe-lwe   |&lt;br /&gt;
    |                    |  2 (default 128)       | after rotate      |&lt;br /&gt;
    | RTO_MIN            | MAX(250 us build-tun-  | RTO floor; also   |&lt;br /&gt;
    |                    |  able, 1&amp;lt;&amp;lt;RXMQ_RES);   | floored at the    |&lt;br /&gt;
    |                    |  per-flow via fccntl   | retransmit-wheel  |&lt;br /&gt;
    |                    |  (FRCTSRTOMIN).        | resolution        |&lt;br /&gt;
    |                    |  Default ~1 ms with    | (~1 ms by         |&lt;br /&gt;
    |                    |  RXMQ_RES=20.          | default).         |&lt;br /&gt;
    | MAX_RTO_MUL        | 20                     | Backoff shift cap |&lt;br /&gt;
    | RACK window R      | MIN(reo_wnd_mult       | Reorder window;   |&lt;br /&gt;
    |                    |  * min_RTT/4, SRTT)    | per RFC 8985      |&lt;br /&gt;
    |                    |  with MIN_REORDER_NS   | sec. 6.2;         |&lt;br /&gt;
    |                    |  = 250 us floor;       | reo_wnd_mult per  |&lt;br /&gt;
    |                    |  reo_wnd_mult scales   | sec. 6.2 step 4   |&lt;br /&gt;
    |                    |  on D-SACK, cap 20     |                   |&lt;br /&gt;
    | MIN_RTT_WIN_NS     | 300 s (5 min, Linux    | min_RTT windowed  |&lt;br /&gt;
    |                    |  tcp_min_rtt_wlen)     | re-anchor         |&lt;br /&gt;
    | REO_WND_MULT_MAX   | 20 (RFC 8985 sec.      | reo_wnd_mult cap  |&lt;br /&gt;
    |                    |  6.2 step 4)           |                   |&lt;br /&gt;
    | REO_DECAY_PKTS     | 16 (RFC 8985 sec.      | Fresh-ACK&#039;d seq   |&lt;br /&gt;
    |                    |  6.2 step 4 /          | count per halving |&lt;br /&gt;
    |                    |  RACK.reo_wnd_persist) |                   |&lt;br /&gt;
    | MAX_DSACK_LAG      | RQ_SIZE                | D-SACK sanity cap |&lt;br /&gt;
    | RTT_QUARANTINE     | 32 (seqno steps)       | NewReno gate pad  |&lt;br /&gt;
    | SACK rate-limit    | SACK_MIN_GAP_NS        | Min SACK gap      |&lt;br /&gt;
    |                    |  (250 us, fixed)       |                   |&lt;br /&gt;
    | SACK_MAX_BLOCKS    | 2048 (wire cap; per-   | Per-SACK block    |&lt;br /&gt;
    |                    |  flow capped at        | cap               |&lt;br /&gt;
    |                    |  (frag_mtu-PCI-4)/8)   |                   |&lt;br /&gt;
    | SACK_RXM_MAX       | 32                     | Per-pass staged   |&lt;br /&gt;
    |                    |                        | retransmit cap    |&lt;br /&gt;
    | DUP_THRESH         | 3 (RFC 8985 default)   | Hybrid fast-rxm   |&lt;br /&gt;
    |                    |                        | trigger (Sec. 8)  |&lt;br /&gt;
    | MDEV_MUL           | 2 (build-tunable via   | mdev shift in     |&lt;br /&gt;
    |                    |  FRCT_RTO_MDEV_-       | RTO = srtt +      |&lt;br /&gt;
    |                    |  MULTIPLIER)           | (mdev &amp;lt;&amp;lt; MDEV_MUL)|&lt;br /&gt;
    | RTTP nonce         | 16 octets              | Echoed verbatim   |&lt;br /&gt;
    | RTTP_RING          | 8                      | In-flight probes  |&lt;br /&gt;
    | RTT clamp          | 16 * srtt              | Probe-sample      |&lt;br /&gt;
    |                    |                        | upper bound       |&lt;br /&gt;
    |                    |                        | (ACK-derived RTT  |&lt;br /&gt;
    |                    |                        | samples gated by  |&lt;br /&gt;
    |                    |                        | Karn / recovery   |&lt;br /&gt;
    |                    |                        | only)             |&lt;br /&gt;
    | Cold-probe cadence | 100 ms (rx-driven;     | Pre-srtt RTTP     |&lt;br /&gt;
    |                    |  see Section 12)       | rate              |&lt;br /&gt;
    | DELT_RDV           | 100 ms                 | RDVS emit cadence |&lt;br /&gt;
    | MAX_RDV            | 1 s                    | RDVS give-up      |&lt;br /&gt;
    | Delayed-ACK fire   | 2 * TICTIME (TICTIME   | Fired after the   |&lt;br /&gt;
    |                    |  = FRCT tick gran-     | first in-order    |&lt;br /&gt;
    |                    |  ularity, default      | DATA arrival;     |&lt;br /&gt;
    |                    |  5 ms; 2*TICTIME       | tick is build-    |&lt;br /&gt;
    |                    |  = 10 ms by default)   | tunable           |&lt;br /&gt;
    | NACK send cooldown | srtt when an srtt      | Pre-DRF NACK      |&lt;br /&gt;
    |                    |  sample exists, else   | rate-limit        |&lt;br /&gt;
    |                    |  100 ms                |                   |&lt;br /&gt;
    | MAX_SDU            | 1 MiB                  | Max reassembled   |&lt;br /&gt;
    |                    |                        | SDU; configurable |&lt;br /&gt;
    |                    |                        | per flow          |&lt;br /&gt;
    +--------------------+------------------------+-------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The per-flow fragment Maximum Transmission Unit (MTU) is computed&lt;br /&gt;
at flow setup from the lower IPCP&#039;s mtu minus encryption&lt;br /&gt;
headsz / tailsz and CRC trailer; there is no FRCT-level default or&lt;br /&gt;
environment-variable override.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 4. Sequence-number rotation (DRF) ==&lt;br /&gt;
&lt;br /&gt;
The DRF (Data Run Flag) bit on an outbound packet means &amp;quot;this is&lt;br /&gt;
the start of a fresh data run&amp;quot; and is set whenever the sender has&lt;br /&gt;
nothing in flight (snd_cr.seqno == snd_cr.lwe).&lt;br /&gt;
&lt;br /&gt;
Independently of that, if the sender has been idle longer than&lt;br /&gt;
snd_cr.inact AND the pipe is empty (snd_cr.seqno == snd_cr.lwe),&lt;br /&gt;
seqno_rotate() rolls a random new seqno before the send and&lt;br /&gt;
resets&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    snd_cr.seqno  = random()&lt;br /&gt;
    snd_cr.lwe    = snd_cr.seqno&lt;br /&gt;
    snd_cr.rwe    = snd_cr.seqno + START_WINDOW&lt;br /&gt;
    rtt_lwe       = snd_cr.seqno&lt;br /&gt;
    in_recovery   = false   (recovery state, see Section 8)&lt;br /&gt;
    recovery_high = snd_cr.seqno&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The receiver, on observing rcv-side inactivity&lt;br /&gt;
(now - rcv_cr.act &amp;gt; rcv_cr.inact), requires a DRF on the next&lt;br /&gt;
DATA packet; otherwise it replies with a rate-limited NACK (see&lt;br /&gt;
below).  Non-DATA control packets pass through without the DRF&lt;br /&gt;
requirement.  On DRF the receiver releases the rq[] slots and&lt;br /&gt;
rebases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    rcv_cr.lwe   = seqno&lt;br /&gt;
    rcv_cr.rwe   = seqno + RQ_SIZE&lt;br /&gt;
    rcv_cr.seqno = seqno&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the inactive packet has DATA but no DRF, a rate-limited NACK is&lt;br /&gt;
fired back to the sender (cooldown per Section 3); non-DATA stale&lt;br /&gt;
arrivals fall through to normal processing (no NACK, no drop).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 5. Send path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    1. If the SDU exceeds (frag_mtu - data_hdr_len), the caller&lt;br /&gt;
       (dev.c) fans it out into ceil(count / (frag_mtu -&lt;br /&gt;
       data_hdr_len)) fragments, each emitted via frcti_snd as its&lt;br /&gt;
       own DATA packet with a per-fragment role (Section 7.2);&lt;br /&gt;
       both FRTX and best-effort flows fragment.  Raw flows (no&lt;br /&gt;
       FRCP engagement, qos.service == SVC_RAW) carry no PCI and&lt;br /&gt;
       return -EMSGSIZE for any SDU larger than one packet at the&lt;br /&gt;
       layer below.  An SDU that fits in a single packet is sent&lt;br /&gt;
       as SOLE.  frcti_snd reserves PCI head room; sets DATA, plus&lt;br /&gt;
       DRF when the pipe is empty (snd_cr.seqno == snd_cr.lwe).&lt;br /&gt;
    2. seqno_rotate() if past sender inactivity and the pipe is&lt;br /&gt;
       empty (Section 4).&lt;br /&gt;
    3. Advertise FC (pci.window = frcti_advert_rwe(frcti), i.e.&lt;br /&gt;
       rcv_cr.rwe clamped to rcv_cr.lwe + ring_seq_cap in stream&lt;br /&gt;
       mode) when the receiver side is recent: now - rcv_cr.act&lt;br /&gt;
       &amp;lt; rcv_cr.inact.&lt;br /&gt;
    4. Reliable mode (FRTX): leave snd_cr.lwe where it is; reset&lt;br /&gt;
       the slot at RQ_SLOT(seqno) (snd_slots[p].time = now,&lt;br /&gt;
       snd_slots[p].flags = 0); queue an rxm_entry (saves a packet&lt;br /&gt;
       copy, arms a wheel timer at now + (rto &amp;lt;&amp;lt; rto_mul)).&lt;br /&gt;
       Piggyback ACK (pci.ackno = rcv_cr.lwe) while the a-timer&lt;br /&gt;
       for the most recent received DATA packet has not yet&lt;br /&gt;
       expired (now - rcv_cr.act &amp;lt;= t_a); on piggyback, set&lt;br /&gt;
       rcv_cr.seqno = rcv_cr.lwe so the next delayed-ACK fire is&lt;br /&gt;
       suppressed.  See Section 8 for t_a / t_r semantics.&lt;br /&gt;
    5. Best-effort mode (no FRTX): advance snd_cr.lwe immediately&lt;br /&gt;
       (snd_cr.lwe = snd_cr.lwe + 1, snd_cr.rwe = snd_cr.lwe +&lt;br /&gt;
       RQ_SIZE); no retransmit state.  No send-side RTT probe is&lt;br /&gt;
       armed in this mode (rtt_probe_arm requires an in-flight&lt;br /&gt;
       seqno, which best-effort never has); the rx-driven cold&lt;br /&gt;
       seeder in frcti_rcv is the only probe path.&lt;br /&gt;
    6. In reliable mode, optionally arm an RTT probe (Section 12).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 6. Receive path ==&lt;br /&gt;
&lt;br /&gt;
=== 6.1. Early-exit dispatch ===&lt;br /&gt;
&lt;br /&gt;
Keepalive (KA), RTT probe (RTTP), pre-DRF NACK, and rendezvous&lt;br /&gt;
(RDVS) packets short-circuit out of frcti_rcv before the locked&lt;br /&gt;
main path; each handler takes its own lock internally.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      incoming packet&lt;br /&gt;
            |&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | KA?     |---yes--&amp;gt; ka_rcv  ; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RTTP?   |---yes--&amp;gt; rttp_rcv; return&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | NACK?   |---yes--&amp;gt; nack_rcv; return  (see Section 9)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       +---------+&lt;br /&gt;
       | RDVS?   |---yes--&amp;gt; rdv_rcv ; return  (reply bare FC, ackno=0)&lt;br /&gt;
       +---------+&lt;br /&gt;
            |no&lt;br /&gt;
            v&lt;br /&gt;
       acquire wrlock; enter locked main path&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - KA   : refresh t_ka_rcv, honour piggybacked ACK.&lt;br /&gt;
  - RTTP : probe (echo back nonce) or echo (verify nonce, sample&lt;br /&gt;
           RTT).&lt;br /&gt;
  - NACK : pre-DRF, sender-side handler.  See Section 9.&lt;br /&gt;
  - RDVS : reply with a bare FC packet (ackno = 0); rdlock only.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 6.2. Locked main path ===&lt;br /&gt;
&lt;br /&gt;
Steps below run with the per-flow frcti.lock held for writing&lt;br /&gt;
(pthread_rwlock_wrlock) unless noted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  rcv_inact_check&lt;br /&gt;
      Only meaningful when the receive side is stale.  On DRF&lt;br /&gt;
      (Data Run Flag): release rq[] slots, rebase rcv_cr, continue.&lt;br /&gt;
      On stale DATA without DRF: fire a pre-DRF NACK if cooldown&lt;br /&gt;
      allows (Section 9), then discard the packet; on cooldown,&lt;br /&gt;
      drop without sending a NACK (a pending cumulative ACK from&lt;br /&gt;
      drop_packet may still go out).  Non-DATA, non-DRF arrivals&lt;br /&gt;
      bypass rcv_inact_check entirely; pure-DRF stale arrivals fall&lt;br /&gt;
      through after the DRF rebase branch.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  DATA-only act refresh&lt;br /&gt;
      Refresh rcv_cr.act only when FRCT_DATA is set, so that non-DATA&lt;br /&gt;
      packets never block the next DRF rebase.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Wire-dup gate&lt;br /&gt;
      Before flag-driven dispatch, drop wire-duplicate ACKs and&lt;br /&gt;
      wire-duplicate DATA (is_dup_ack / is_dup_data).  The DATA&lt;br /&gt;
      check is bypassed for FRCT_RXM-bearing arrivals so the&lt;br /&gt;
      piggybacked ACK / SACK / FC carried on a retransmitted DATA&lt;br /&gt;
      at an already-ACK&#039;d seqno is still applied; the stale-in-&lt;br /&gt;
      window branch below then drops the packet.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ACK&lt;br /&gt;
      Drop ACKs whose ackno falls outside (snd_cr.lwe, snd_cr.seqno].&lt;br /&gt;
      If ackno == snd_cr.lwe (non-advancing cumulative ACK), drive&lt;br /&gt;
      RACK fast-retransmit consideration (Section 8).  Otherwise&lt;br /&gt;
      advance snd_cr.lwe = ackno, collapse rto_mul to 0 (Karn-gated&lt;br /&gt;
      by SND_RTX on the just-acknowledged slot, the old head-of-&lt;br /&gt;
      line), reset dup_thresh to 0, update t_latest_ack to the&lt;br /&gt;
      send-time of the slot at ackno-1 (consumed by RACK and SACK&lt;br /&gt;
      below), decay reo_wnd_mult per RFC 8985 sec. 6.2 step 4,&lt;br /&gt;
      exit NewReno-careful recovery (see Section 8) on&lt;br /&gt;
      ackno &amp;gt;= recovery_high or ackno == snd_cr.seqno, and feed an&lt;br /&gt;
      RTT sample if eligible (Section 12).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  SACK&lt;br /&gt;
      Walk the block list.  For each block (a present range above&lt;br /&gt;
      lwe) NULL out snd_slots[k].rxm, clear the slot&#039;s per-send&lt;br /&gt;
      flags, and advance t_latest_ack to the latest send-time&lt;br /&gt;
      covered (the Forward Acknowledgement / fack equivalent,&lt;br /&gt;
      Mathis &amp;amp; Mahdavi 1996); the first block whose start&lt;br /&gt;
      clamps to snd_cr.lwe skips this fack update so that a head-&lt;br /&gt;
      of-line clamp does not falsely advance fack.  For un-SACKed&lt;br /&gt;
      gaps below hi_sacked, stage a retransmit per slot that is&lt;br /&gt;
      (1) still owned (rxm != NULL), (2) not already SND_FAST_RXM,&lt;br /&gt;
      (3) not aged out past t_r, and (4) either outside the RACK&lt;br /&gt;
      reorder window R OR with dup_thresh &amp;gt;= DUP_THRESH (the RFC&lt;br /&gt;
      8985 sec. 6.2 hybrid trigger).  Mark the slot SND_FAST_RXM&lt;br /&gt;
      and NULL the rxm at stage time.  Capped at SACK_RXM_MAX&lt;br /&gt;
      staged retransmits per receive pass; what&#039;s left rides the&lt;br /&gt;
      next SACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  FC&lt;br /&gt;
      Bump snd_cr.rwe (clamped to lwe + RQ_SIZE, never shrinks)&lt;br /&gt;
      and mark window open.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  DATA&lt;br /&gt;
      Bounds-check seqno against window.  On stale-dup&lt;br /&gt;
      (seqno &amp;lt; rcv_cr.lwe), set rcv_cr.seqno = seqno to force a&lt;br /&gt;
      fresh ACK on the next ack_snd, then drop.  On accept: both&lt;br /&gt;
      FRTX and best-effort stash the packet-buffer index into&lt;br /&gt;
      rq[seqno mod RQ_SIZE].  Fragments stash unchanged - the role&lt;br /&gt;
      bits are inspected only at consume time (Section 7.2).  On&lt;br /&gt;
      out-of-order arrival, build a SACK reply if not rate-limited&lt;br /&gt;
      (per Section 3) and not deduplicated against the previous&lt;br /&gt;
      (rcv_cr.lwe, n_blocks) pair; D-SACK reports always bypass the&lt;br /&gt;
      dedup.  If both rate-limit and dedup suppress the reply,&lt;br /&gt;
      neither SACK nor delayed-ACK fires (the sender picks up the&lt;br /&gt;
      gap on its next ACK).  On in-order arrival, arm the delayed-&lt;br /&gt;
      ACK timer.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  drop_packet exit&lt;br /&gt;
      Releases the per-packet shared-memory buffer (spb), then&lt;br /&gt;
      calls ack_snd synchronously after the spb release to surface&lt;br /&gt;
      any pending cumulative ACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Read path and reassembly ==&lt;br /&gt;
&lt;br /&gt;
=== 7.1. Read path ===&lt;br /&gt;
&lt;br /&gt;
flow_read returns a full reassembled SDU (Service Data Unit) via&lt;br /&gt;
frcti_consume on every FRCP SDU-mode flow (FRTX or best-effort);&lt;br /&gt;
stream-mode is covered in Section 16.  An incomplete head-of-line&lt;br /&gt;
(HoL) run yields -EAGAIN; an oversized run yields -EMSGSIZE (the&lt;br /&gt;
run is dropped so the flow does not stall).  On best-effort flows,&lt;br /&gt;
a permanently-lost mid-fragment is dropped as soon as a later&lt;br /&gt;
complete SDU becomes visible in the ring (Section 7.2 skip-past-&lt;br /&gt;
gap).&lt;br /&gt;
&lt;br /&gt;
Raw flows carry no frcti, so flow_read returns the next pending&lt;br /&gt;
packet-buffer index directly, with no role-bit inspection.  (Raw&lt;br /&gt;
service is selected via qos.service == SVC_RAW at flow allocation,&lt;br /&gt;
which suppresses frcti creation.)&lt;br /&gt;
&lt;br /&gt;
frcti_pdu_ready is the no-advance peek used by fevent (the&lt;br /&gt;
Ouroboros flow-event multiplexer, the poll(2)-equivalent on&lt;br /&gt;
flows).  It returns ready only when the head-of-line run is&lt;br /&gt;
complete and the lead packet (a Protocol Data Unit, here one FRCP&lt;br /&gt;
packet) is present at rcv_cr.rwe - RQ_SIZE; any other state&lt;br /&gt;
(including the best-effort skip-past-gap case) returns not ready,&lt;br /&gt;
and frcti_consume is left to drop the broken prefix and re-&lt;br /&gt;
inspect.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7.2. Fragmentation and reassembly ===&lt;br /&gt;
&lt;br /&gt;
Send side (flow_write_frag).  An SDU larger than&lt;br /&gt;
(frag_mtu - PCI) is split into ceil(count / (frag_mtu - PCI))&lt;br /&gt;
fragments; each fragment is its own FRCP packet with its own&lt;br /&gt;
seqno and a per-fragment role flag pair (Section 1.2).  Roles are&lt;br /&gt;
assigned at emit time:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +------+--------+&lt;br /&gt;
    | i    | Role   |&lt;br /&gt;
    +------+--------+&lt;br /&gt;
    | n=1  | SOLE   |&lt;br /&gt;
    | i=0  | FIRST  |&lt;br /&gt;
    | i=n-1| LAST   |&lt;br /&gt;
    | else | MID    |&lt;br /&gt;
    +------+--------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A mid-loop allocation or transmit failure may yield a partial&lt;br /&gt;
write: the call returns the bytes already enqueued (off &amp;gt; 0) or&lt;br /&gt;
the underlying error (off == 0).  Best-effort flows fragment&lt;br /&gt;
identically; on the receiver, a partial run with a permanently-&lt;br /&gt;
lost fragment is dropped when a later complete SDU is visible in&lt;br /&gt;
the ring (see skip-past-gap below).  Raw flows carry no PCI and&lt;br /&gt;
refuse anything larger than the layer&#039;s user MTU (-EMSGSIZE).&lt;br /&gt;
&lt;br /&gt;
Wire-level recovery is fragment-agnostic on FRTX flows: each&lt;br /&gt;
fragment&#039;s seqno flows through SACK / RACK / RTO / NACK exactly&lt;br /&gt;
as for a SOLE DATA packet, and reassembly does not re-enter the&lt;br /&gt;
loss-detection path.  Best-effort flows run the same seqno&lt;br /&gt;
machinery (DRF, FC, ACK piggyback, pre-DRF NACK emit) but queue&lt;br /&gt;
no rxm state at the sender, so a lost MID is unrecoverable;&lt;br /&gt;
skip-past-gap handles it (below).&lt;br /&gt;
&lt;br /&gt;
Receive side.  Fragments stash into rq[seqno] unchanged; role bits&lt;br /&gt;
are read only at consume time.  frag_run_inspect, called from&lt;br /&gt;
frcti_consume, walks the ring starting at the oldest still-&lt;br /&gt;
undelivered seqno base = rcv_cr.rwe - RQ_SIZE (equal to rcv_cr.lwe&lt;br /&gt;
only when no partial run is in progress; during a partial run lwe&lt;br /&gt;
has already advanced past base).  It produces one of three&lt;br /&gt;
outcomes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
    | Outcome       | Cause                                       |&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
    | DELIVER (n)   | rq[base]=SOLE (n=1), or rq[base]=FIRST and  |&lt;br /&gt;
    |               | a LAST follows in slots [base+1..base+n-1]  |&lt;br /&gt;
    |               | with all intermediate roles in {MID,FIRST,  |&lt;br /&gt;
    |               | LAST} contiguous.                           |&lt;br /&gt;
    | DROP (n)      | rq[base] is MID or LAST without a preceding |&lt;br /&gt;
    |               | FIRST (n=1); a FIRST..[non-LAST]..new-FIRST |&lt;br /&gt;
    |               | or new-SOLE mid-run (drop the broken prefix |&lt;br /&gt;
    |               | with n = run length minus 1, so the new     |&lt;br /&gt;
    |               | FIRST/SOLE stays); or, on best-effort       |&lt;br /&gt;
    |               | flows, a gap at base with a FIRST/SOLE      |&lt;br /&gt;
    |               | later in the ring (drop up to the new run   |&lt;br /&gt;
    |               | start).                                     |&lt;br /&gt;
    | NOT_READY     | rq[base] absent or FIRST..[non-LAST] with   |&lt;br /&gt;
    |               | no later FIRST/SOLE in the ring (FRTX waits |&lt;br /&gt;
    |               | for retx; best-effort waits for arrival).   |&lt;br /&gt;
    +---------------+---------------------------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
DELIVER triggers frag_gather: a scatter-gather memcpy of the n&lt;br /&gt;
consecutive fragments at rq[base..base+n-1] directly into the&lt;br /&gt;
caller&#039;s buffer; each per-packet shared-memory buffer (spb) is&lt;br /&gt;
released and rwe advances by n.  lwe was already advanced&lt;br /&gt;
incrementally as each contiguous fragment arrived; frag_gather&lt;br /&gt;
only restores the fixed-width invariant rwe == lwe + RQ_SIZE.&lt;br /&gt;
No intermediate reassembly buffer is allocated.&lt;br /&gt;
&lt;br /&gt;
DROP advances rwe past the broken prefix (releasing the spbs)&lt;br /&gt;
and pulls lwe up to the new trailing edge if needed; the next&lt;br /&gt;
consume retries from the new base.  Oversize or arithmetically&lt;br /&gt;
overflowing delivery (sum of fragment lengths &amp;gt; max_rcv_sdu, sum&lt;br /&gt;
&amp;gt; caller&#039;s buffer, or running-sum overflow) also drops the run&lt;br /&gt;
with -EMSGSIZE.&lt;br /&gt;
&lt;br /&gt;
Skip-past-gap (best-effort only).  On FRTX, a gap in the run means&lt;br /&gt;
&amp;quot;waiting for retransmit&amp;quot; and frag_run_inspect returns NOT_READY.&lt;br /&gt;
On best-effort flows the gap is permanent, so frag_run_inspect&lt;br /&gt;
scans forward in the ring for the next FIRST or SOLE; if one is&lt;br /&gt;
visible within RQ_SIZE, it returns DROP for the broken prefix and&lt;br /&gt;
the consume loop retries at the new lwe.  Memory hold is bounded&lt;br /&gt;
by RQ_SIZE; the partial releases on the next consume call once a&lt;br /&gt;
later complete run exists.  Voice-like flows (one SOLE per SDU)&lt;br /&gt;
see no extra wait: any later SOLE makes the prior gap droppable&lt;br /&gt;
immediately.&lt;br /&gt;
&lt;br /&gt;
The choice to defer reassembly to consume time keeps the receive&lt;br /&gt;
path zero-copy: fragments stay in the shared-memory ring until&lt;br /&gt;
the application pulls, and the SDU lands directly in the caller&#039;s&lt;br /&gt;
buffer.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 8. Retransmission ==&lt;br /&gt;
&lt;br /&gt;
FRCP is bounded by two delta-t-derived timers (Watson 1981, see&lt;br /&gt;
Section 15):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - t_a (a-timer): upper bound on ACK delay.  An ACK for a received&lt;br /&gt;
    DATA packet MUST be emitted within t_a of receipt; an attempt&lt;br /&gt;
    to send an ACK after the a-timer has expired is suppressed&lt;br /&gt;
    (the sender&#039;s RTO is already in motion).&lt;br /&gt;
  - t_r (r-timer): upper bound on retransmission.  A given DATA&lt;br /&gt;
    packet MUST NOT be retransmitted after t_r has elapsed since&lt;br /&gt;
    its first send (t0); when the bound is hit, the flow is&lt;br /&gt;
    declared down (raising the Ouroboros asynchronous flow&lt;br /&gt;
    condition ACL_FLOWDOWN, which marks the flow dead to both&lt;br /&gt;
    endpoints) rather than retransmitted again.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each in-flight FRTX seqno owns one rxm_entry, armed in a hashed&lt;br /&gt;
timing wheel; the wheel deadline is the slot&#039;s next eligible&lt;br /&gt;
retransmit time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  RTO timer&lt;br /&gt;
      On fire (rxm_due), re-emit with FRCT_RXM, mark SND_RTX&lt;br /&gt;
      (Karn-suppress next ACK&#039;s RTT sample), and (for the head-of-&lt;br /&gt;
      line (HoL) slot only) bump rto_mul up to MAX_RTO_MUL.  Wheel&lt;br /&gt;
      deadline is t_send + (rto &amp;lt;&amp;lt; rto_mul).  Re-armed unless&lt;br /&gt;
      consumed.  The RTO timer also clears SND_FAST_RXM (re-arming&lt;br /&gt;
      fast-retransmit eligibility), resets reo_wnd_mult to 1 on a&lt;br /&gt;
      HoL fire (RFC 8985 sec. 6.2 step 4 reset clause), and marks&lt;br /&gt;
      the flow ACL_FLOWDOWN if its frct_tx call fails.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  r-timer guard&lt;br /&gt;
      Before any retransmit attempt, check (now - t0) against t_r.&lt;br /&gt;
      If exceeded, the slot is no longer eligible for retransmit.&lt;br /&gt;
      Only the RTO timer (rxm_due) treats r-timer expiry as&lt;br /&gt;
      terminal: it marks the flow ACL_FLOWDOWN (peer unreachable).&lt;br /&gt;
      Fast-retransmit, SACK-driven retransmit, and NACK-driven&lt;br /&gt;
      head-of-line re-emit silently skip aged-out slots and defer&lt;br /&gt;
      the flow-down decision to the next RTO fire.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Fast retransmit (hybrid trigger, RFC 8985 sec. 6.2)&lt;br /&gt;
      On a non-advancing cumulative ACK with the scoreboard&lt;br /&gt;
      advanced, fire one fast retransmit when EITHER (a) the head-&lt;br /&gt;
      of-line slot&#039;s latest send is older than the RACK reorder&lt;br /&gt;
      window R (Section 3) and not yet aged out, OR (b) the SACK&lt;br /&gt;
      dup-thresh count above snd_cr.lwe reaches DUP_THRESH (= 3,&lt;br /&gt;
      RFC 8985 sec. 6.2 step 4).  Fires at most once per non-&lt;br /&gt;
      advancing cumulative-ACK value, gated by rack_fired_lwe (the&lt;br /&gt;
      snd_cr.lwe at which fast-retransmit last fired).  Set&lt;br /&gt;
      SND_FAST_RXM on the slot (one-shot per-slot gate) and enter&lt;br /&gt;
      NewReno-style careful recovery (see NewReno below in this&lt;br /&gt;
      section).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      The RACK reorder window R uses the RFC 8985 sec. 6.2 form&lt;br /&gt;
      R = MIN(reo_wnd_mult * min_RTT / 4, SRTT) with a&lt;br /&gt;
      MIN_REORDER_NS = 250 us floor.  Before the first RTT sample&lt;br /&gt;
      seeds min_rtt, R falls back to MIN(reo_wnd_mult * SRTT / 4,&lt;br /&gt;
      SRTT), still floored at MIN_REORDER_NS (consistent with the&lt;br /&gt;
      windowed-minimum fallback described in Section 12).  min_rtt&lt;br /&gt;
      is a windowed minimum over the last MIN_RTT_WIN_NS = 5 min of&lt;br /&gt;
      RTT samples (matches the Linux tcp_min_rtt_wlen default) so a&lt;br /&gt;
      route change to a longer path eventually re-anchors the&lt;br /&gt;
      reorder window without relying on reo_wnd_mult growth alone.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  SACK-driven retransmit&lt;br /&gt;
      For each gap below hi_sacked whose slot is (1) still owned,&lt;br /&gt;
      (2) not already SND_FAST_RXM, (3) not aged out past t_r, and&lt;br /&gt;
      (4) either outside the RACK window R OR with dup_thresh &amp;gt;=&lt;br /&gt;
      DUP_THRESH (same hybrid as fast-retransmit, see Section 6.2),&lt;br /&gt;
      re-emit.  Each SACK-driven retransmit re-arms a fresh rxm so&lt;br /&gt;
      a lost retransmit can still be recovered by its own RTO&lt;br /&gt;
      timer.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  NewReno&lt;br /&gt;
      On entry, recovery_high = snd_cr.seqno + RTT_QUARANTINE.&lt;br /&gt;
      Exit when ackno &amp;gt;= recovery_high or ackno == snd_cr.seqno&lt;br /&gt;
      (the latter means everything sent has been acknowledged).&lt;br /&gt;
      seqno_rotate also clears recovery.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Pre-DRF NACK ==&lt;br /&gt;
&lt;br /&gt;
The two sides have different inactivity thresholds&lt;br /&gt;
(snd_cr.inact &amp;gt; rcv_cr.inact), so a receiver can detect &amp;quot;stale data&lt;br /&gt;
run&amp;quot; before the sender&#039;s own DRF logic kicks in.  NACK is the&lt;br /&gt;
receiver-driven nudge that asks the sender to re-transmit the head&lt;br /&gt;
of the run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Send (frcti_nack_snd, called by frcti_rcv when rcv_inact_check&lt;br /&gt;
        returns FRCT_INACT_NEED_NACK)&lt;br /&gt;
      When an incoming DATA packet has no DRF and rcv-side activity&lt;br /&gt;
      is older than rcv_cr.inact, the receiver emits a bare packet&lt;br /&gt;
      with flags = FRCT_NACK and seqno = arrival_seqno - 1&lt;br /&gt;
      (informational only, not consulted by the receive handler).&lt;br /&gt;
      The cooldown in Section 3 rate-limits the burst.  Non-DATA&lt;br /&gt;
      non-DRF arrivals bypass rcv_inact_check entirely; non-DATA&lt;br /&gt;
      DRF still rebases via the DRF branch.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Receive (frcti_nack_rcv)&lt;br /&gt;
      Dispatched in the early-exit branch (Section 6.1), before&lt;br /&gt;
      rcv_inact_check.  The sender copies the head-of-line (HoL)&lt;br /&gt;
      rxm packet, marks the slot SND_RTX | SND_FAST_RXM (Karn-&lt;br /&gt;
      suppress next ACK, one-shot fast-rxm gate), sets rtt_lwe =&lt;br /&gt;
      snd_cr.lwe + 1, and re-emits via fast_rxm_send with FRCT_RXM&lt;br /&gt;
      and a refreshed ackno.  The original rxm_entry and its RTO&lt;br /&gt;
      timer are left armed - the NACK emit is additive to the&lt;br /&gt;
      normal retransmit machinery, not a replacement.  No-op if&lt;br /&gt;
      nothing is in flight, the HoL slot has aged past t_r, or&lt;br /&gt;
      the HoL rxm pointer has been cleared by SACK or RACK.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NACK serves two roles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  1. Lost first-of-run (DRF) packet recovery.  Required.  Until&lt;br /&gt;
     the DRF packet arrives, the receiver cannot rebase its&lt;br /&gt;
     window, so any subsequent in-flight packets look stale to&lt;br /&gt;
     the receiver.  The NACK fires the moment the second&lt;br /&gt;
     packet arrives at a stale receiver, telling the sender to&lt;br /&gt;
     re-emit the HoL (DRF) packet at NACK-cooldown latency rather&lt;br /&gt;
     than waiting for the initial RTO (which is the configured&lt;br /&gt;
     default until srtt is seeded by the first probe round-trip).&lt;br /&gt;
  2. General loss-recovery accelerator.  When loss is detected&lt;br /&gt;
     receiver-first, the NACK skips one RTO of latency relative to&lt;br /&gt;
     waiting for the sender&#039;s RTO to fire.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In both cases the existing rxm_entry and its RTO timer are left&lt;br /&gt;
armed, so the RTO path remains the eventual fallback.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 10. Cumulative + selective ACK ==&lt;br /&gt;
&lt;br /&gt;
Cumulative ACK is ackno = rcv_cr.lwe.  On out-of-order arrival the&lt;br /&gt;
receiver also emits a SACK packet (Section 1.3) whose payload lists&lt;br /&gt;
*present* blocks above lwe (analogous to TCP SACK / QUIC ACK&lt;br /&gt;
ranges).  SACKs are rate-limited per Section 3 and suppressed when&lt;br /&gt;
neither lwe nor block count has changed since the last SACK.&lt;br /&gt;
&lt;br /&gt;
D-SACK reports (RFC 2883) are emitted in-band as block[0] of an&lt;br /&gt;
otherwise normal SACK frame (see Section 1.3 for the encoding).&lt;br /&gt;
Two receiver triggers arm a pending D-SACK report (single-slot,&lt;br /&gt;
latest-wins):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - DATA arrival with seqno &amp;lt; rcv_cr.lwe, both wire-dup (no RXM,&lt;br /&gt;
    is_dup_data path) and retransmit (RXM, post-FC branch)&lt;br /&gt;
    (RFC 2883 sec. 4.1.1, full duplicate)&lt;br /&gt;
  - rq_accept conflict, slot already occupied in [lwe, rwe)&lt;br /&gt;
    (RFC 2883 sec. 4.1.2, partial duplicate)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a D-SACK is pending and the standard scoreboard SACK would be&lt;br /&gt;
suppressed by dedup or rate-limit, the report is emitted as a&lt;br /&gt;
stand-alone SACK frame through the normal ack_snd path; when a&lt;br /&gt;
D-SACK report is pending the path bypasses dedup and the TICTIME&lt;br /&gt;
rate-limit, but the a-timer suppression on rcv inactivity still&lt;br /&gt;
applies.&lt;br /&gt;
&lt;br /&gt;
Bare ACKs are deferred via a per-flow delayed-ACK timer (one in&lt;br /&gt;
flight at a time, atomic test-and-set dedup; fires per Section 3&lt;br /&gt;
after the first in-order arrival).  Suppressed if (1) no new&lt;br /&gt;
seqno, (2) rcv side is inactive (older than t_a), or (3) the&lt;br /&gt;
sender just sent within TICTIME.  A pending D-SACK ride-through&lt;br /&gt;
bypasses (1) and (3); the a-timer gate (2) is unconditional.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 11. Flow control ==&lt;br /&gt;
&lt;br /&gt;
The receiver advertises rwe in every FC field.  The sender treats&lt;br /&gt;
its snd_cr.rwe as the absolute right edge: when&lt;br /&gt;
snd_cr.seqno &amp;gt;= snd_cr.rwe the window is closed and flow_write&lt;br /&gt;
yields.  While closed, the sender periodically emits RDVS&lt;br /&gt;
(rendezvous) packets (cadence DELT_RDV); the receiver replies with&lt;br /&gt;
a bare FC packet (ackno = 0) that reopens the window.  Once the&lt;br /&gt;
window has been closed for longer than MAX_RDV the sender stops&lt;br /&gt;
emitting RDVS but does not tear the flow down - the writer keeps&lt;br /&gt;
blocking until either a peer-driven FC arrives or the KA&lt;br /&gt;
(keepalive) / r-timer marks the flow.&lt;br /&gt;
&lt;br /&gt;
rwe is clamped to lwe + RQ_SIZE on receipt and MUST NOT shrink:&lt;br /&gt;
a backward rwe is silently clamped to the current snd_cr.rwe;&lt;br /&gt;
the FC packet still reopens the window.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 12. RTT estimation ==&lt;br /&gt;
&lt;br /&gt;
Active RTTP probes (Section 1.4) carry a 32-bit probe_id (0&lt;br /&gt;
reserved) and a 16-byte random nonce echoed verbatim - defends&lt;br /&gt;
against spoofed replies.  A ring of RTTP_RING in-flight probes is&lt;br /&gt;
kept; an echo whose (id, nonce) doesn&#039;t match the ring slot is&lt;br /&gt;
dropped.  A single RTTP sample is clamped to RTT_CLAMP_MUL * srtt&lt;br /&gt;
(compile-time RTT_CLAMP_MUL = 16) once srtt is seeded; the first&lt;br /&gt;
cold-probe sample feeds rtt_update raw.&lt;br /&gt;
&lt;br /&gt;
Probe arming gates:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Cold (no srtt yet): the receive path arms at most one probe&lt;br /&gt;
    per 100 ms via frcti_rcv_probe (PROBE_DUE_COLD); arming&lt;br /&gt;
    requires an incoming packet.  Active send-path arming bails&lt;br /&gt;
    while srtt == 0.&lt;br /&gt;
  - Warm (rtt_probe_arm, called from frcti_snd): outstanding&lt;br /&gt;
    data (snd_cr.seqno &amp;gt; snd_cr.lwe), AND at least 2 * srtt&lt;br /&gt;
    since t_rcv_rtt (last RTT receive of any kind), AND at&lt;br /&gt;
    least srtt since t_snd_probe (last probe emit).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sample feeds either Linux&#039;s asymmetric mdev estimator&lt;br /&gt;
(FRCT_LINUX_RTT_ESTIMATOR, default ON) or RFC 6298 symmetric EWMA&lt;br /&gt;
(compile option).  srtt is floored at 10 ms when seeded from a&lt;br /&gt;
hint, at 1 us after every update (including the first seeding&lt;br /&gt;
sample); mdev floored at 100 ns.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    RTO = max(rto_min, 2 * srtt, srtt + (mdev &amp;lt;&amp;lt; MDEV_MUL))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(the 2 * srtt floor is an FRCT addition not in RFC 6298).&lt;br /&gt;
Effective wheel deadline capped per Section 3.&lt;br /&gt;
&lt;br /&gt;
ACK-derived samples (frcti_ack_rcv -&amp;gt; rtt_sample_eligible), beyond&lt;br /&gt;
the cum-ACK advance gate in frcti_ack_rcv (ackno &amp;gt; lwe and&lt;br /&gt;
ackno &amp;lt;= seqno), require all of: not in recovery; ACK packet does&lt;br /&gt;
not carry FRCT_RXM; HoL slot&#039;s SND_RTX bit clear; slot&#039;s rxm&lt;br /&gt;
pointer non-NULL (not SACK-consumed); lwe not below the rtt_lwe&lt;br /&gt;
fence; srtt already seeded by an RTTP probe.  There is no ACK-only&lt;br /&gt;
seeding.&lt;br /&gt;
&lt;br /&gt;
Every eligible sample also feeds RACK.min_RTT (RFC 8985 sec. 6.2)&lt;br /&gt;
via a windowed minimum: replace whenever the sample is strictly&lt;br /&gt;
smaller OR more than MIN_RTT_WIN_NS (5 min, matches Linux&lt;br /&gt;
tcp_min_rtt_wlen) has elapsed since the current min was set.  The&lt;br /&gt;
downward branch is immediate (faster path picked up at once); the&lt;br /&gt;
upward branch is gated on the window (a transient queue burst does&lt;br /&gt;
not poison the estimate, but a sustained route change to a longer&lt;br /&gt;
path re-anchors min_RTT after at most one window).  Seeded from&lt;br /&gt;
rtt_hint at rtt_init; 0 acts as the unset sentinel and the base&lt;br /&gt;
in rack_reorder_window falls back from min_RTT to SRTT (so&lt;br /&gt;
R = mult * SRTT/4, capped at SRTT, floored at MIN_REORDER_NS)&lt;br /&gt;
until the first sample.  See Section 6.2.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 13. Liveness (keepalive) ==&lt;br /&gt;
&lt;br /&gt;
When qs.timeout &amp;gt; 0 a per-flow KA (keepalive) timer is armed.&lt;br /&gt;
Arming uses rcv_cr.act for the deadline computation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    deadline = min(snd_act + qs.timeout/4,&lt;br /&gt;
                   rcv_act + qs.timeout)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(clamped to now + qs.timeout/4 if already past).  The timer fires&lt;br /&gt;
either on sender idleness (to send a KA) or on receiver idleness&lt;br /&gt;
(to declare the peer dead).  On fire (ka_snd) the peer-dead test&lt;br /&gt;
uses max(rcv_cr.act, t_ka_rcv) so a recent KA reply counts even&lt;br /&gt;
when no DATA has arrived:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - If now - max(rcv_cr.act, t_ka_rcv) &amp;gt; qs.timeout, mark the flow&lt;br /&gt;
    ACL_FLOWPEER and notify the per-process flow-event set&lt;br /&gt;
    (proc.fqset) with FLOW_PEER.&lt;br /&gt;
  - Else if snd_idle &amp;gt; qs.timeout/4, emit a bare KA | ACK&lt;br /&gt;
    (ackno = rcv_cr.lwe) and re-arm.&lt;br /&gt;
  - Else just re-arm.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: rx_rb and tx_rb are the receive and transmit shared-memory&lt;br /&gt;
ring buffers.  The r-timer raises ACL_FLOWDOWN on both (route is&lt;br /&gt;
broken); keepalive raises ACL_FLOWPEER on rx_rb only and notifies&lt;br /&gt;
the flow-event set (peer is silent, writer keeps tx_rb usable) -&lt;br /&gt;
distinct ACLs.  qs.timeout == 0 disables keepalive entirely; a&lt;br /&gt;
silent peer crash is then undetected.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 14. Linger / teardown ==&lt;br /&gt;
&lt;br /&gt;
On flow_dealloc, frcti_dealloc computes a grace timeout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    max(rcv_cr.act + rcv_cr.inact, snd_cr.act + snd_cr.inact) - now&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(floored at 0 and converted to seconds) and returns it; flow_dealloc&lt;br /&gt;
forwards this to the IRMd as the dealloc grace.  The IRMd, not FRCT,&lt;br /&gt;
performs the wait.  Before computing the timeout, FRCT may emit a&lt;br /&gt;
final ACK when rcv_cr.lwe != rcv_cr.seqno (the peer has not been&lt;br /&gt;
told the most recent cumulative ACK) AND the rcv side has been&lt;br /&gt;
active within t_a (a-timer not aged out).&lt;br /&gt;
&lt;br /&gt;
FRCTFLINGER is honoured only when snd_cr.lwe &amp;lt; edge, where edge =&lt;br /&gt;
snd_fin_seqno after FIN has been sent in stream mode and&lt;br /&gt;
snd_cr.seqno otherwise (data or FIN still in flight).  The drain&lt;br /&gt;
itself runs in flow_dealloc&#039;s while (FRCTI_LINGERING) loop, not in&lt;br /&gt;
frcti_dealloc.&lt;br /&gt;
&lt;br /&gt;
The fd is single-reader / single-writer (documented in the&lt;br /&gt;
manpages).  flow_write pumps rx_rb on every call (via&lt;br /&gt;
flow_wait_window -&amp;gt; flow_drain_rx_nb) and additionally blocks on&lt;br /&gt;
rx_rb when the send window is closed.  A pure-writer thread thus&lt;br /&gt;
consumes ACKs without a dedicated reader.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 15. Heritage and adopted techniques ==&lt;br /&gt;
&lt;br /&gt;
Delta-t (Watson, 1981) is the primary heritage; FRCP descends from&lt;br /&gt;
the delta-t protocol family via the Recursive InterNetwork&lt;br /&gt;
Architecture (RINA; Day, &amp;quot;Patterns in Network Architecture&amp;quot;, 2008,&lt;br /&gt;
ch. 9).  Timer-based connection management&lt;br /&gt;
(no SYN/FIN handshake, per-flow state born on first DATA and&lt;br /&gt;
reclaimed after t_mpl + a + r of silence), the DRF marker, and the&lt;br /&gt;
t_mpl / t_a / t_r timers all come from delta-t.  See Watson,&lt;br /&gt;
&amp;quot;Timer-Based Mechanisms in Reliable Transport Protocol Connection&lt;br /&gt;
Management&amp;quot;, Computer Networks 5 (1981).&lt;br /&gt;
&lt;br /&gt;
The unified `flow_alloc(name, qos, ...)` primitive and its&lt;br /&gt;
multi-axis QoS-cube argument (Section 2.2) also come from RINA&lt;br /&gt;
(Day 2008, ch. 6; Grasa et al., &amp;quot;IRATI: investigating RINA as an&lt;br /&gt;
alternative to TCP/IP&amp;quot;, Computer Networks 92 (2015)) - reliability,&lt;br /&gt;
ordering, CRC presence, and encryption are flow attributes, not&lt;br /&gt;
separate sockets or protocols.&lt;br /&gt;
&lt;br /&gt;
The table below summarises additional adopted techniques and their&lt;br /&gt;
references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| FRCP mechanism         | Heritage         | Reference / note       |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Random new seqno on    | TCP ISN          | RFC 6528 (Gont &amp;amp;       |&lt;br /&gt;
| seqno_rotate           |                  | Bellovin, 2012).       |&lt;br /&gt;
|                        |                  | QUIC PN-space reset    |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 12.3)   |&lt;br /&gt;
|                        |                  | is a structural        |&lt;br /&gt;
|                        |                  | analogue.              |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Cumulative ACK,        | TCP              | RFC 793 / RFC 9293     |&lt;br /&gt;
| left-window-edge       |                  |                        |&lt;br /&gt;
| advance                |                  |                        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Receive window with    | TCP              | RFC 793 sec. 3.7 /     |&lt;br /&gt;
| non-shrink rule        |                  | RFC 9293 sec. 3.8.6;   |&lt;br /&gt;
|                        |                  | RFC 1122 sec. 4.2.2.16 |&lt;br /&gt;
|                        |                  | for the explicit non-  |&lt;br /&gt;
|                        |                  | shrink prohibition     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Modular seqno          | TCP              | RFC 793 sec. 3.3 /     |&lt;br /&gt;
| arithmetic             |                  | RFC 9293 sec. 3.4      |&lt;br /&gt;
| (before/after helpers) |                  |                        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Selective ACK block    | TCP              | RFC 2018 (Mathis et    |&lt;br /&gt;
| list                   |                  | al., 1996).  Encoded   |&lt;br /&gt;
|                        |                  | as a typed FRCP packet |&lt;br /&gt;
|                        |                  | rather than a TCP      |&lt;br /&gt;
|                        |                  | option, so framing is  |&lt;br /&gt;
|                        |                  | closer to QUIC ACK     |&lt;br /&gt;
|                        |                  | frames.  D-SACK (RFC   |&lt;br /&gt;
|                        |                  | 2883) carried in-band  |&lt;br /&gt;
|                        |                  | as block[0]; see       |&lt;br /&gt;
|                        |                  | Section 1.3.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| NewReno-careful        | TCP              | RFC 6582 (Henderson    |&lt;br /&gt;
| recovery with          |                  | et al., 2012); QUIC    |&lt;br /&gt;
| recovery_high gate     |                  | builds on the same     |&lt;br /&gt;
|                        |                  | model in RFC 9002      |&lt;br /&gt;
|                        |                  | sec. 7.3.2.  Cwnd half |&lt;br /&gt;
|                        |                  | absent (CC in IPCP).   |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| RACK reordering        | TCP              | RFC 8985 (Cheng et     |&lt;br /&gt;
| window for fast        |                  | al., 2021).  FRCP      |&lt;br /&gt;
| retransmit             |                  | R = MIN(reo_wnd_mult * |&lt;br /&gt;
|                        |                  | min_RTT / 4, SRTT)     |&lt;br /&gt;
|                        |                  | with a MIN_REORDER_NS  |&lt;br /&gt;
|                        |                  | = 250 us floor against |&lt;br /&gt;
|                        |                  | srtt collapse; matches |&lt;br /&gt;
|                        |                  | RFC 8985 sec. 6.2 and  |&lt;br /&gt;
|                        |                  | Linux tcp_rack_reo_wnd.|&lt;br /&gt;
|                        |                  | DSACK-driven           |&lt;br /&gt;
|                        |                  | reo_wnd_mult (sec. 6.2 |&lt;br /&gt;
|                        |                  | step 4) is adopted;    |&lt;br /&gt;
|                        |                  | see Section 1.3 for    |&lt;br /&gt;
|                        |                  | the wire encoding.     |&lt;br /&gt;
|                        |                  | The hybrid RACK-or-    |&lt;br /&gt;
|                        |                  | DUP_THRESH trigger     |&lt;br /&gt;
|                        |                  | from RFC 8985 sec. 6.2 |&lt;br /&gt;
|                        |                  | step 4 is adopted      |&lt;br /&gt;
|                        |                  | (Section 8).  QUIC&#039;s   |&lt;br /&gt;
|                        |                  | analogue in RFC 9002   |&lt;br /&gt;
|                        |                  | sec. 6.1.2 uses        |&lt;br /&gt;
|                        |                  | max(srtt, latest_rtt)  |&lt;br /&gt;
|                        |                  | as the base.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Karn&#039;s algorithm:      | TCP              | Karn &amp;amp; Partridge,      |&lt;br /&gt;
| no RTT sample on       |                  | &amp;quot;Improving Round-Trip  |&lt;br /&gt;
| retransmits, RTO-      |                  | Time Estimates in      |&lt;br /&gt;
| collapse freeze        |                  | Reliable Transport     |&lt;br /&gt;
|                        |                  | Protocols&amp;quot;, SIGCOMM    |&lt;br /&gt;
|                        |                  | 1987; RFC 6298 sec. 3. |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| RTO formula            | TCP              | RFC 6298 (Paxson et    |&lt;br /&gt;
| RTO = max(RTO_MIN,     |                  | al., 2011).  RTO_MIN = |&lt;br /&gt;
| srtt + (mdev &amp;lt;&amp;lt;        |                  | 5 ms is below RFC 6298 |&lt;br /&gt;
| MDEV_MUL))             |                  | sec. 2.4&#039;s 1 s SHOULD- |&lt;br /&gt;
|                        |                  | floor - a recursive-   |&lt;br /&gt;
|                        |                  | layer choice.          |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Linux asymmetric mdev  | Linux kernel     | tcp_rtt_estimator() in |&lt;br /&gt;
| estimator (default)    |                  | net/ipv4/tcp_input.c;  |&lt;br /&gt;
|                        |                  | the if(delta&amp;lt;0) m&amp;gt;&amp;gt;=3  |&lt;br /&gt;
|                        |                  | dampening is a         |&lt;br /&gt;
|                        |                  | kernel divergence from |&lt;br /&gt;
|                        |                  | RFC 6298.  RFC 6298    |&lt;br /&gt;
|                        |                  | EWMA available behind  |&lt;br /&gt;
|                        |                  | a compile flag.        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Delayed ACK with rate  | TCP              | RFC 813 (Clark, 1982); |&lt;br /&gt;
| suppression            |                  | RFC 1122 sec. 4.2.3.2; |&lt;br /&gt;
|                        |                  | RFC 5681 sec. 4.2.     |&lt;br /&gt;
|                        |                  | Single-deadline        |&lt;br /&gt;
|                        |                  | coalescing rather than |&lt;br /&gt;
|                        |                  | &amp;quot;ack-every-other-      |&lt;br /&gt;
|                        |                  | segment&amp;quot;.              |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Zero-window-probe /    | TCP              | RFC 1122 sec.          |&lt;br /&gt;
| persist-timer          |                  | 4.2.2.17 / RFC 9293    |&lt;br /&gt;
| analogue (RDVS)        |                  | sec. 3.8.6.1.  RDVS    |&lt;br /&gt;
|                        |                  | solicits an FC reply,  |&lt;br /&gt;
|                        |                  | distinct from QUIC     |&lt;br /&gt;
|                        |                  | DATA_BLOCKED (RFC 9000 |&lt;br /&gt;
|                        |                  | sec. 19.12), which is  |&lt;br /&gt;
|                        |                  | one-way notification.  |&lt;br /&gt;
|                        |                  | MAX_RDV give-up        |&lt;br /&gt;
|                        |                  | departs from TCP.      |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Multiplexed control    | SCTP / QUIC      | SCTP chunk bundling    |&lt;br /&gt;
| on a single PCI        |                  | (RFC 9260 sec. 6.10);  |&lt;br /&gt;
|                        |                  | QUIC frame             |&lt;br /&gt;
|                        |                  | multiplexing (RFC 9000 |&lt;br /&gt;
|                        |                  | sec. 12.4).  Cleaner   |&lt;br /&gt;
|                        |                  | fit than TCP&#039;s         |&lt;br /&gt;
|                        |                  | separate-flag-bits     |&lt;br /&gt;
|                        |                  | design.                |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| ACK ranges as          | QUIC             | QUIC ACK frame (RFC    |&lt;br /&gt;
| multiple discontiguous |                  | 9000 sec. 19.3).  FRCP |&lt;br /&gt;
| acked blocks           |                  | SACK is conceptually   |&lt;br /&gt;
|                        |                  | QUIC-frame-shaped      |&lt;br /&gt;
|                        |                  | even though encoded    |&lt;br /&gt;
|                        |                  | as absolute            |&lt;br /&gt;
|                        |                  | [start,end] pairs.     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Nonce-authenticated    | QUIC             | PATH_CHALLENGE /       |&lt;br /&gt;
| active RTT / liveness  | PATH_CHALLENGE   | PATH_RESPONSE (RFC     |&lt;br /&gt;
| probing (RTTP)         |                  | 9000 sec. 8.2,         |&lt;br /&gt;
|                        |                  | sec. 19.17, sec.       |&lt;br /&gt;
|                        |                  | 19.18).  WebRTC ICE    |&lt;br /&gt;
|                        |                  | consent-freshness      |&lt;br /&gt;
|                        |                  | (RFC 7675) is the      |&lt;br /&gt;
|                        |                  | same pattern.  QUIC&#039;s  |&lt;br /&gt;
|                        |                  | nonce is 8 octets;     |&lt;br /&gt;
|                        |                  | FRCP chooses 16.       |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Probing distinct from  | QUIC             | KA timer answers       |&lt;br /&gt;
| keepalive              |                  | &amp;quot;peer alive?&amp;quot;, RTTP    |&lt;br /&gt;
|                        |                  | answers &amp;quot;path          |&lt;br /&gt;
|                        |                  | measurable?&amp;quot;, as in    |&lt;br /&gt;
|                        |                  | QUIC PING (RFC 9000    |&lt;br /&gt;
|                        |                  | sec. 19.2) vs          |&lt;br /&gt;
|                        |                  | PATH_CHALLENGE.        |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Bare KA + ACK          | QUIC / SCTP      | QUIC PING (RFC 9000    |&lt;br /&gt;
| keepalive packets      |                  | sec. 19.2); SCTP       |&lt;br /&gt;
|                        |                  | HEARTBEAT /            |&lt;br /&gt;
|                        |                  | HEARTBEAT-ACK (RFC     |&lt;br /&gt;
|                        |                  | 9260 sec. 8.3).  SCTP  |&lt;br /&gt;
|                        |                  | HEARTBEAT also carries |&lt;br /&gt;
|                        |                  | an opaque echoed blob, |&lt;br /&gt;
|                        |                  | structurally similar   |&lt;br /&gt;
|                        |                  | to FRCP RTTP.          |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| (FFGM, LFGM)           | SCTP             | RFC 9260 sec. 3.3.1    |&lt;br /&gt;
| fragment-role bits     |                  | DATA chunk B/E bits    |&lt;br /&gt;
| (Section 7.2)          |                  | encode the same four   |&lt;br /&gt;
|                        |                  | states (B+E=SOLE,      |&lt;br /&gt;
|                        |                  | B-only=FIRST, neither  |&lt;br /&gt;
|                        |                  | =MID, E-only=LAST).    |&lt;br /&gt;
|                        |                  | Each fragment carries  |&lt;br /&gt;
|                        |                  | its own seqno/TSN and  |&lt;br /&gt;
|                        |                  | is independently       |&lt;br /&gt;
|                        |                  | retransmitted.         |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Stream byte-offset     | QUIC             | QUIC STREAM frame      |&lt;br /&gt;
| reassembly             |                  | (RFC 9000 sec. 19.8)   |&lt;br /&gt;
| (Sections 1.5, 16)     |                  | uses Offset + Length   |&lt;br /&gt;
|                        |                  | varints; FRCP uses     |&lt;br /&gt;
|                        |                  | fixed 32-bit start /   |&lt;br /&gt;
|                        |                  | end.  One stream per   |&lt;br /&gt;
|                        |                  | flow vs QUIC&#039;s many    |&lt;br /&gt;
|                        |                  | streams multiplexed.   |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| FIN end-of-stream      | TCP / QUIC       | TCP FIN flag (RFC 9293 |&lt;br /&gt;
| marker                 |                  | sec. 3.1) closes one   |&lt;br /&gt;
| (Sections 1.2, 16)     |                  | half of the byte       |&lt;br /&gt;
|                        |                  | stream; QUIC STREAM    |&lt;br /&gt;
|                        |                  | frame FIN bit (RFC     |&lt;br /&gt;
|                        |                  | 9000 sec. 19.8) does   |&lt;br /&gt;
|                        |                  | the same per stream    |&lt;br /&gt;
|                        |                  | with an immutable      |&lt;br /&gt;
|                        |                  | final-size invariance  |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 4.5:    |&lt;br /&gt;
|                        |                  | the final size is      |&lt;br /&gt;
|                        |                  | fixed once observed).  |&lt;br /&gt;
|                        |                  | FRCP&#039;s FIN consumes    |&lt;br /&gt;
|                        |                  | one packet seqno (not  |&lt;br /&gt;
|                        |                  | one byte of stream     |&lt;br /&gt;
|                        |                  | space) and is          |&lt;br /&gt;
|                        |                  | idempotent on the      |&lt;br /&gt;
|                        |                  | sender side.           |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Stream byte-credit     | QUIC             | MAX_STREAM_DATA (RFC   |&lt;br /&gt;
| flow control           |                  | 9000 sec. 4.1, sec.    |&lt;br /&gt;
| (Section 16)           |                  | 19.10).  FRCP projects |&lt;br /&gt;
|                        |                  | a per-flow byte budget |&lt;br /&gt;
|                        |                  | onto the seqno-space   |&lt;br /&gt;
|                        |                  | rwe.  Single stream    |&lt;br /&gt;
|                        |                  | per flow collapses     |&lt;br /&gt;
|                        |                  | QUIC&#039;s MAX_DATA /      |&lt;br /&gt;
|                        |                  | MAX_STREAM_            |&lt;br /&gt;
|                        |                  | DATA distinction.      |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Header protection      | QUIC             | QUIC RFC 9001 sec. 5.4 |&lt;br /&gt;
| (encrypted seqnos)     |                  | applies header         |&lt;br /&gt;
|                        |                  | protection on top of   |&lt;br /&gt;
|                        |                  | AEAD to mask the       |&lt;br /&gt;
|                        |                  | packet number.  FRCP&#039;s |&lt;br /&gt;
|                        |                  | per-flow AEAD wrap     |&lt;br /&gt;
|                        |                  | (Section 16) is wider: |&lt;br /&gt;
|                        |                  | it encrypts the entire |&lt;br /&gt;
|                        |                  | PCI including seqno    |&lt;br /&gt;
|                        |                  | because the IPCP       |&lt;br /&gt;
|                        |                  | below already routes,  |&lt;br /&gt;
|                        |                  | so no destination      |&lt;br /&gt;
|                        |                  | connection-ID needs to |&lt;br /&gt;
|                        |                  | stay in clear (cf.     |&lt;br /&gt;
|                        |                  | RFC 9000 sec. 5.2).    |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Two-bit fragment role  | SCTP             | The (FFGM, LFGM) pair  |&lt;br /&gt;
| polarity               |                  | follows SCTP B/E       |&lt;br /&gt;
|                        |                  | (begin = 1 / end = 1)  |&lt;br /&gt;
|                        |                  | rather than IPv4 MF    |&lt;br /&gt;
|                        |                  | (RFC 791 sec. 3.2),    |&lt;br /&gt;
|                        |                  | which has the inverse  |&lt;br /&gt;
|                        |                  | polarity (MF = 1 means |&lt;br /&gt;
|                        |                  | NOT last).             |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Orthogonal reliability | SCTP             | PR-SCTP (RFC 3758,     |&lt;br /&gt;
| / ordering axes        |                  | per-message partial    |&lt;br /&gt;
| (Section 2.2)          |                  | reliability) and SCTP  |&lt;br /&gt;
|                        |                  | DATA U-bit (RFC 9260   |&lt;br /&gt;
|                        |                  | sec. 3.3.1, per-       |&lt;br /&gt;
|                        |                  | message unordered)     |&lt;br /&gt;
|                        |                  | are the closest        |&lt;br /&gt;
|                        |                  | precedents for         |&lt;br /&gt;
|                        |                  | decoupling reliability |&lt;br /&gt;
|                        |                  | from ordering; FRCP    |&lt;br /&gt;
|                        |                  | sets them per-flow     |&lt;br /&gt;
|                        |                  | rather than per-       |&lt;br /&gt;
|                        |                  | message.               |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Orthogonal CRC         | UDP-Lite         | RFC 3828 (Larzon et    |&lt;br /&gt;
| (qs.ber == 0)          |                  | al., 2004) lets the    |&lt;br /&gt;
|                        |                  | sender pick a per-     |&lt;br /&gt;
|                        |                  | packet Checksum        |&lt;br /&gt;
|                        |                  | Coverage and the       |&lt;br /&gt;
|                        |                  | receiver enforce a     |&lt;br /&gt;
|                        |                  | locally configured     |&lt;br /&gt;
|                        |                  | minimum (no in-band    |&lt;br /&gt;
|                        |                  | negotiation; sec. 3.1, |&lt;br /&gt;
|                        |                  | sec. 3.3).  FRCP       |&lt;br /&gt;
|                        |                  | gates a full CRC       |&lt;br /&gt;
|                        |                  | trailer on qs.ber == 0 |&lt;br /&gt;
|                        |                  | at flow setup.         |&lt;br /&gt;
|                        |                  | Contrast TCP / SCTP    |&lt;br /&gt;
|                        |                  | (mandatory checksum)   |&lt;br /&gt;
|                        |                  | and QUIC (AEAD         |&lt;br /&gt;
|                        |                  | subsumes CRC).         |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
| Setup-time service     | DCCP / SCTP /    | DCCP Service Codes     |&lt;br /&gt;
| negotiation            | QUIC             | (RFC 4340 sec. 8.1.2,  |&lt;br /&gt;
|                        |                  | RFC 5595); SCTP INIT   |&lt;br /&gt;
|                        |                  | parameters (RFC 9260   |&lt;br /&gt;
|                        |                  | sec. 3.3.2); QUIC      |&lt;br /&gt;
|                        |                  | transport parameters   |&lt;br /&gt;
|                        |                  | (RFC 9000 sec. 7.4).   |&lt;br /&gt;
|                        |                  | All negotiate service  |&lt;br /&gt;
|                        |                  | properties at          |&lt;br /&gt;
|                        |                  | connection setup; only |&lt;br /&gt;
|                        |                  | RINA&#039;s QoS cube        |&lt;br /&gt;
|                        |                  | exposes them as an     |&lt;br /&gt;
|                        |                  | orthogonal vector.     |&lt;br /&gt;
+------------------------+------------------+------------------------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.1. Original to FRCP (no clean prior art) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Pre-DRF NACK (Section 9): receiver-driven nudge exploiting&lt;br /&gt;
    snd_cr.inact &amp;gt; rcv_cr.inact.  Closest analogues are SCTP Gap Ack&lt;br /&gt;
    Blocks (RFC 9260 sec. 3.3.4) and DCCP Ack Vector (RFC 4340&lt;br /&gt;
    sec. 11.4) - both let the receiver describe gaps to the sender,&lt;br /&gt;
    but neither targets the cross-epoch / pre-DRF case.&lt;br /&gt;
  - MAX_RDV window-probe give-up: neither TCP (persist-timer&lt;br /&gt;
    probes until application or R2 abort, RFC 9293 sec. 3.8.6.1)&lt;br /&gt;
    nor QUIC has an explicit FC-give-up counter.  A recursive-&lt;br /&gt;
    network choice: outer layers can drop the flow.&lt;br /&gt;
  - Skip-past-gap reassembly (Section 7.2): SCTP fragments and&lt;br /&gt;
    reassembles every flow regardless of reliability/ordering,&lt;br /&gt;
    using its own per-stream reassembly queue; QUIC fragments via&lt;br /&gt;
    STREAM offsets.  FRCP fragments best-effort flows too, but&lt;br /&gt;
    the receiver drops the broken prefix the moment a later run-&lt;br /&gt;
    start (FIRST or SOLE role) is visible inside the RQ_SIZE-wide&lt;br /&gt;
    reorder ring - no IP-frag-style timeout, no SCTP-style&lt;br /&gt;
    explicit abort.  If no later run-start arrives within the&lt;br /&gt;
    ring, frag_run_inspect returns NOT_READY and the partial run&lt;br /&gt;
    keeps its slots; the next inspect retries.  The trade-off: a&lt;br /&gt;
    permanently-lost MID in a long isolated run holds slots until&lt;br /&gt;
    either a later FIRST/SOLE appears in the ring or the writer&lt;br /&gt;
    stops, at which point the slots are reclaimed on flow&lt;br /&gt;
    teardown.&lt;br /&gt;
  - Reassembly deferred to consume time (Section 7.2), message&lt;br /&gt;
    mode only (qos.service == SVC_MESSAGE): SCTP (RFC 9260&lt;br /&gt;
    sec. 6.9), QUIC (RFC 9000 sec. 2.2), and TCP (RFC 9293) all&lt;br /&gt;
    hold reassembly state at the receive boundary.  FRCP message-&lt;br /&gt;
    mode leaves fragments in the shared-memory ring until&lt;br /&gt;
    flow_read pulls and lands the SDU directly in the caller&#039;s&lt;br /&gt;
    buffer.  Stream mode (Section 16) uses the standard QUIC-&lt;br /&gt;
    style direct ring placement on receive and does not defer.&lt;br /&gt;
    The optimisation is enabled by the Shared-Memory Subsystem&lt;br /&gt;
    (SSM) packet-buffer ring (see struct ssm_pk_buff at&lt;br /&gt;
    Section 1.1); the analogue is OS-level scatter-gather I/O&lt;br /&gt;
    (recvmsg+iovec), not a transport-layer prior art.&lt;br /&gt;
  - TLP-equivalent tail-loss recovery (RFC 8985 sec. 7;&lt;br /&gt;
    RFC 9002 sec. 6.2): FRCP does not emit an explicit Tail Loss&lt;br /&gt;
    Probe packet, but the same goal is met implicitly by RACK&lt;br /&gt;
    loss detection (Section 8) firing on a non-advancing&lt;br /&gt;
    cumulative ACK once the head-of-line slot ages past the RACK&lt;br /&gt;
    reorder window R = MIN(reo_wnd_mult * min_RTT / 4, SRTT) -&lt;br /&gt;
    well below RTO = max(2 * SRTT, SRTT + (mdev &amp;lt;&amp;lt; MDEV_MUL)).&lt;br /&gt;
    A receiver-driven nudge is also available via the pre-DRF&lt;br /&gt;
    NACK (Section 9).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 15.2. Not adopted ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Slow start, congestion window (cwnd), Additive Increase /&lt;br /&gt;
    Multiplicative Decrease (AIMD), NewReno cwnd inflation.&lt;br /&gt;
    Congestion control lives in the IPCP CA policies and is&lt;br /&gt;
    driven by Explicit Congestion Notification (ECN, RFC 3168).&lt;br /&gt;
  - Nagle / silly-window-syndrome (SWS) avoidance (RFC 896, RFC&lt;br /&gt;
    1122 sec. 4.2.3.4).  (Deferred work, not adopted in the&lt;br /&gt;
    current spec.)&lt;br /&gt;
  - TCP Timestamps (RFC 7323) / Protection Against Wrapped&lt;br /&gt;
    Sequences (PAWS) - RTT measurement uses RTTP,&lt;br /&gt;
    not per-segment timestamps.  A peer-supplied timestamp echoed&lt;br /&gt;
    on every ACK lets a malicious peer drive the srtt estimate&lt;br /&gt;
    arbitrarily low, collapsing the RTO and triggering a self-&lt;br /&gt;
    inflicted retransmit storm.  RTTP confines RTT measurement to&lt;br /&gt;
    nonce-authenticated probe round-trips, where a forged echo is&lt;br /&gt;
    rejected before it can reach the estimator.&lt;br /&gt;
  - ECN (Explicit Congestion Notification) response inside FRCP&lt;br /&gt;
    (consumed by IPCP Congestion Avoidance / CA).&lt;br /&gt;
  - IP-style fragment-offset reassembly (RFC 791 sec. 3.2; RFC 8200&lt;br /&gt;
    sec. 4.5).  Message-mode FRCP relies on the FRCT rq[] reorder&lt;br /&gt;
    ring keyed by seqno (shared by FRTX and best-effort flows) to&lt;br /&gt;
    put fragments back in order; no separate offset field is&lt;br /&gt;
    needed and no IP-style hole-list reassembly buffer is kept.&lt;br /&gt;
    Stream-mode FRCP does carry [start, end) byte offsets&lt;br /&gt;
    (Section 1.5) for direct ring placement on receive.&lt;br /&gt;
  - QUIC STREAM offset+length framing on *every* flow (RFC 9000&lt;br /&gt;
    sec. 19.8).  Message-mode FRCP uses the SCTP-style B/E flag-&lt;br /&gt;
    bit encoding (FFGM/LFGM) and skips the offsets; stream-mode&lt;br /&gt;
    FRCP adopts the QUIC offset model (heritage table above).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 16. Stream-mode flows ==&lt;br /&gt;
&lt;br /&gt;
When a flow is allocated with qos.service == SVC_STREAM both peers&lt;br /&gt;
switch to byte-stream semantics, layered on top of the FRTX reorder&lt;br /&gt;
machinery already described in Sections 6-8.&lt;br /&gt;
&lt;br /&gt;
=== 16.1. Send ===&lt;br /&gt;
&lt;br /&gt;
The sender splits the caller&#039;s octets into chunks of at most&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension) octets (Sections 1.1&lt;br /&gt;
and 1.5).  Each chunk is one DATA packet with its own seqno and a&lt;br /&gt;
[start, end) byte range copied from a monotonic stream counter.&lt;br /&gt;
In stream mode FFGM and LFGM are unused and MUST be transmitted as&lt;br /&gt;
zero; the per-byte position is carried by the [start, end)&lt;br /&gt;
extension instead.&lt;br /&gt;
&lt;br /&gt;
End-of-stream is signalled with a 0-byte DATA packet that has FIN&lt;br /&gt;
(bit 12) set, emitted on the FIN triggers listed in Section 1.2&lt;br /&gt;
(WR-half close, flow_dealloc, and any other path that yields the&lt;br /&gt;
final byte).  The sender MUST emit at most one FIN per flow; its&lt;br /&gt;
[start, end) MUST equal [final-byte, final-byte) (i.e., empty&lt;br /&gt;
interval at the final byte position; final-size invariance,&lt;br /&gt;
analogous to QUIC RFC 9000 sec. 4.5).  Idempotency is enforced by&lt;br /&gt;
an snd_fin_sent guard.&lt;br /&gt;
&lt;br /&gt;
=== 16.2. Receive ===&lt;br /&gt;
&lt;br /&gt;
On arrival the receiver places the payload directly into a per-flow&lt;br /&gt;
byte-indexed receive ring of width ring_sz (octets) at the position&lt;br /&gt;
indicated by start, with a two-segment memcpy across the ring&lt;br /&gt;
boundary if needed.  Receipt is recorded in the FRTX reorder&lt;br /&gt;
machinery (Section 6.2) augmented with the packet&#039;s start, end, and&lt;br /&gt;
FIN bit per slot.  When a packet&#039;s [start, end) front-overlaps&lt;br /&gt;
bytes already at or below the byte high-water mark, the overlap is&lt;br /&gt;
trimmed before placement so the same byte is never written twice.&lt;br /&gt;
After stashing, the receiver advances lwe and the byte high-water&lt;br /&gt;
mark across any newly-contiguous prefix.  Each slot advanced MUST&lt;br /&gt;
satisfy `start == the last-delivered slot&#039;s end`; a slot whose&lt;br /&gt;
start does not equal that end is silently dropped at delivery time&lt;br /&gt;
(the seqno is consumed, no stream bytes contributed) and the high-&lt;br /&gt;
water mark does not advance past it.  The stream byte-stream&lt;br /&gt;
stalls at that point - there is no flow-tear-down on mismatch.&lt;br /&gt;
This filters spliced or off-path-injected slots that fall in&lt;br /&gt;
window without strong cryptographic authentication.&lt;br /&gt;
&lt;br /&gt;
A FIN slot marks end-of-stream at advance time only if its byte&lt;br /&gt;
position equals the last-delivered slot&#039;s end; otherwise the FIN&lt;br /&gt;
is ignored and the corresponding seqno occupies a slot but&lt;br /&gt;
contributes no stream bytes.  No packet buffer is held after the&lt;br /&gt;
ring copy.&lt;br /&gt;
&lt;br /&gt;
=== 16.3. Read ===&lt;br /&gt;
&lt;br /&gt;
flow_read returns up to count octets from the contiguous prefix&lt;br /&gt;
[next, high-water), where next is the byte the application has&lt;br /&gt;
already consumed up to and high-water is the rightmost contiguous&lt;br /&gt;
byte received.  When the stream is fully drained AND end-of-stream&lt;br /&gt;
(EOS) was observed (next == EOS byte position), flow_read returns&lt;br /&gt;
0 (EOF) - the same shape POSIX read(2) uses on TCP after a peer&lt;br /&gt;
FIN.&lt;br /&gt;
&lt;br /&gt;
=== 16.4. Flow control ===&lt;br /&gt;
&lt;br /&gt;
ACK / SACK / RACK / RTO machinery is unchanged; the FRTX reorder&lt;br /&gt;
ring is reused as a per-seqno received-bitmap.  Let per_pkt =&lt;br /&gt;
(frag_mtu - base PCI - stream PCI extension), the maximum stream-&lt;br /&gt;
byte payload one DATA packet can carry (Section 16.1).  The&lt;br /&gt;
receive window advertised in FC is clamped so the byte window&lt;br /&gt;
(ring_sz) cannot be overrun: the seqno-space rwe is at most&lt;br /&gt;
`rcv_cr.lwe + ring_sz / per_pkt`.&lt;br /&gt;
&lt;br /&gt;
This is the QUIC byte-credit flow-control model&lt;br /&gt;
(MAX_STREAM_DATA, RFC 9000 sec. 4.1 and sec. 19.10) projected onto&lt;br /&gt;
seqno space.  With one stream per flow there is no MAX_DATA /&lt;br /&gt;
MAX_STREAM_DATA distinction.  Receiver-side silly-window-syndrome&lt;br /&gt;
(SWS) avoidance (RFC 9293 sec. 3.8.6.2.2) is achieved by combining&lt;br /&gt;
the consume-time rwe bump with the global non-shrink rule from&lt;br /&gt;
Section 11.&lt;br /&gt;
&lt;br /&gt;
=== 16.5. Security considerations ===&lt;br /&gt;
&lt;br /&gt;
Threat model.  An attacker that can observe (on-path passive) or&lt;br /&gt;
predict (off-path blind) the flow&#039;s seqnos and byte offsets on an&lt;br /&gt;
unencrypted stream flow can inject DATA or FIN at any in-window&lt;br /&gt;
position.  The in-line consistency checks above (start == prior&lt;br /&gt;
end on advance; FIN MUST be 0-byte; FIN MUST sit at the final&lt;br /&gt;
byte position) realise the spirit of RFC 5961&#039;s &amp;quot;sequence-window&lt;br /&gt;
plus exact-position match for control bits&amp;quot; without an explicit&lt;br /&gt;
challenge-ACK probe; they make a few specific blind attack shapes&lt;br /&gt;
harder but are not cryptographic authentication. This is&lt;br /&gt;
comparable to TCP without the TCP Authentication Option (TCP-AO,&lt;br /&gt;
RFC 5925), tighter than a&lt;br /&gt;
pre-RFC-5961 TCP stack, and roughly equivalent to a modern&lt;br /&gt;
RFC 5961 stack against blind off-path injection - none of these&lt;br /&gt;
help once the attacker can sniff. TLS over TCP (RFC 8446)&lt;br /&gt;
encrypts only the TCP payload and leaves TCP seqnos, ACKs, FIN,&lt;br /&gt;
and RST in the clear, so TLS does NOT defend against TCP-header-&lt;br /&gt;
level injection; QUIC (RFC 9000) hides packet numbers under&lt;br /&gt;
header protection (RFC 9001 sec. 5.4), so this specific weakness&lt;br /&gt;
does not apply to QUIC.&lt;br /&gt;
&lt;br /&gt;
Mitigation: AEAD.  When the flow has encryption enabled the&lt;br /&gt;
recommended AEAD ciphers (AES-GCM, RFC 5288; or ChaCha20-Poly1305,&lt;br /&gt;
RFC 8439) wrap the entire FRCP packet on the wire - PCI, stream&lt;br /&gt;
extension, body, and the CRC trailer when ber == 0 - under a&lt;br /&gt;
per-flow symmetric key derived from the flow&#039;s own key exchange&lt;br /&gt;
(Section 1.1).  The AEAD tag (~2^-128 forgery probability)&lt;br /&gt;
dominates the CRC (~2^-32) for integrity in this mode but the CRC&lt;br /&gt;
trailer is currently retained inside the wrap (see Section 1.1).&lt;br /&gt;
Implementations MUST NOT rely on the security properties below&lt;br /&gt;
when a non-AEAD cipher (e.g. AES-CTR alone) is negotiated; non-&lt;br /&gt;
AEAD modes provide confidentiality only and the threat-model&lt;br /&gt;
claims do not hold.&lt;br /&gt;
&lt;br /&gt;
With an AEAD cipher in use, seqnos, byte offsets, and the FIN bit&lt;br /&gt;
are both authenticated and confidential. Against an off-path or&lt;br /&gt;
on-path-passive attacker this is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - Stronger than TCP+TLS (TCP header in the clear).&lt;br /&gt;
  - Stronger than TCP+TCP-AO (header authenticated but visible).&lt;br /&gt;
  - Comparable to IPsec ESP transport mode (RFC 4303), which&lt;br /&gt;
    similarly authenticates and encrypts the upper-layer header&lt;br /&gt;
    plus payload, and to QUIC packet protection (RFC 9001 sec. 5),&lt;br /&gt;
    with the difference that QUIC must leave the destination&lt;br /&gt;
    connection ID in the clear for routing whereas FRCP relies on&lt;br /&gt;
    the IPCP below for delivery and can therefore encrypt its&lt;br /&gt;
    entire PCI.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Keying granularity.  FRCP runs key exchange (kex) per flow, so&lt;br /&gt;
each flow_alloc yields independent symmetric keys.  This is&lt;br /&gt;
finer-grained than QUIC (per-connection, RFC 9001, where one&lt;br /&gt;
handshake covers all multiplexed streams) and finer-grained than&lt;br /&gt;
typical IPsec deployment (per-host-pair Security Associations,&lt;br /&gt;
SAs).  Forward secrecy follows from the kex when an ephemeral&lt;br /&gt;
Diffie-Hellman exchange (DHE), or a hybrid mode (classical DH +&lt;br /&gt;
post-quantum Key Encapsulation Mechanism / KEM), is selected.&lt;br /&gt;
&lt;br /&gt;
Replay protection.  The AEAD layer itself does NOT carry an&lt;br /&gt;
explicit anti-replay window (unlike IPsec ESP, RFC 4303 sec.&lt;br /&gt;
3.4.3, or DTLS, RFC 9147 sec. 4.5.1).  For FRCP-engaged flows the&lt;br /&gt;
seqno-space duplicate-suppression in Section 6.2 rejects replayed&lt;br /&gt;
DATA after the AEAD strips the wrap, because the AEAD authenticates&lt;br /&gt;
the seqno and a replay re-presents an old seqno that is then&lt;br /&gt;
discarded either as a duplicate (still inside the receive window)&lt;br /&gt;
or as outside the receive window, depending on how far lwe has&lt;br /&gt;
advanced since the original packet was delivered.  RAW&lt;br /&gt;
(qos.service == SVC_RAW) flows have no FRCP layer and therefore&lt;br /&gt;
no replay protection at the AEAD layer either; deployments that&lt;br /&gt;
need replay rejection on RAW flows MUST provide it at a higher&lt;br /&gt;
layer.&lt;br /&gt;
&lt;br /&gt;
Layering.  The AEAD wrap sits below FRCP on the data path, so&lt;br /&gt;
RAW best-effort flows (qos.service == SVC_RAW, the UDP-equivalent&lt;br /&gt;
service of Section 2.2) inherit the same per-flow integrity +&lt;br /&gt;
confidentiality scope as FRCP-engaged flows - whatever the IPCP&lt;br /&gt;
and FRCP (if any) put on the wire is what the AEAD authenticates.&lt;br /&gt;
No DTLS-equivalent layering is required for confidentiality and&lt;br /&gt;
integrity; replay protection above AEAD is a separate concern as&lt;br /&gt;
noted above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 17. References ==&lt;br /&gt;
&lt;br /&gt;
This section lists the IETF documents, published works, and&lt;br /&gt;
source-code references cited inline elsewhere in this document.&lt;br /&gt;
IETF documents are cited inline as &amp;quot;RFC NNNN sec. X.Y&amp;quot;; books,&lt;br /&gt;
journal papers, and source-code references are cited inline by&lt;br /&gt;
author and year (or by file and function name) and are listed&lt;br /&gt;
here for convenience.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.1. IETF documents ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 791]   J. Postel, &amp;quot;Internet Protocol&amp;quot;, STD 5, RFC 791,&lt;br /&gt;
              September 1981.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 793]   J. Postel, &amp;quot;Transmission Control Protocol&amp;quot;, STD 7,&lt;br /&gt;
              RFC 793, September 1981.  Obsoleted by RFC 9293.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 813]   D. D. Clark, &amp;quot;Window and Acknowledgement Strategy&lt;br /&gt;
              in TCP&amp;quot;, RFC 813, July 1982.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 896]   J. Nagle, &amp;quot;Congestion Control in IP/TCP&lt;br /&gt;
              Internetworks&amp;quot;, RFC 896, January 1984.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 1122]  R. Braden (ed.), &amp;quot;Requirements for Internet Hosts&lt;br /&gt;
              -- Communication Layers&amp;quot;, STD 3, RFC 1122,&lt;br /&gt;
              October 1989.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2018]  M. Mathis, J. Mahdavi, S. Floyd, A. Romanow,&lt;br /&gt;
              &amp;quot;TCP Selective Acknowledgment Options&amp;quot;, RFC 2018,&lt;br /&gt;
              October 1996.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2119]  S. Bradner, &amp;quot;Key words for use in RFCs to Indicate&lt;br /&gt;
              Requirement Levels&amp;quot;, BCP 14, RFC 2119, March 1997.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 2883]  S. Floyd, J. Mahdavi, M. Mathis, M. Podolsky,&lt;br /&gt;
              &amp;quot;An Extension to the Selective Acknowledgement&lt;br /&gt;
              (SACK) Option for TCP&amp;quot;, RFC 2883, July 2000.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 3758]  R. Stewart, M. Ramalho, Q. Xie, M. Tuexen,&lt;br /&gt;
              P. Conrad, &amp;quot;Stream Control Transmission Protocol&lt;br /&gt;
              (SCTP) Partial Reliability Extension&amp;quot;, RFC 3758,&lt;br /&gt;
              May 2004.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 3828]  L-A. Larzon, M. Degermark, S. Pink, L-E. Jonsson&lt;br /&gt;
              (ed.), G. Fairhurst (ed.), &amp;quot;The Lightweight User&lt;br /&gt;
              Datagram Protocol (UDP-Lite)&amp;quot;, RFC 3828,&lt;br /&gt;
              July 2004.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 4303]  S. Kent, &amp;quot;IP Encapsulating Security Payload&lt;br /&gt;
              (ESP)&amp;quot;, RFC 4303, December 2005.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 4340]  E. Kohler, M. Handley, S. Floyd, &amp;quot;Datagram&lt;br /&gt;
              Congestion Control Protocol (DCCP)&amp;quot;, RFC 4340,&lt;br /&gt;
              March 2006.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5288]  J. Salowey, A. Choudhury, D. McGrew, &amp;quot;AES Galois&lt;br /&gt;
              Counter Mode (GCM) Cipher Suites for TLS&amp;quot;,&lt;br /&gt;
              RFC 5288, August 2008.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5595]  G. Fairhurst, &amp;quot;The Datagram Congestion Control&lt;br /&gt;
              Protocol (DCCP) Service Codes&amp;quot;, RFC 5595,&lt;br /&gt;
              September 2009.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5681]  M. Allman, V. Paxson, E. Blanton, &amp;quot;TCP Congestion&lt;br /&gt;
              Control&amp;quot;, RFC 5681, September 2009.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5925]  J. Touch, A. Mankin, R. Bonica, &amp;quot;The TCP&lt;br /&gt;
              Authentication Option&amp;quot;, RFC 5925, June 2010.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 5961]  A. Ramaiah, R. Stewart, M. Dalal, &amp;quot;Improving&lt;br /&gt;
              TCP&#039;s Robustness to Blind In-Window Attacks&amp;quot;,&lt;br /&gt;
              RFC 5961, August 2010.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6298]  V. Paxson, M. Allman, J. Chu, M. Sargent,&lt;br /&gt;
              &amp;quot;Computing TCP&#039;s Retransmission Timer&amp;quot;, RFC 6298,&lt;br /&gt;
              June 2011.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6528]  F. Gont, S. Bellovin, &amp;quot;Defending against Sequence&lt;br /&gt;
              Number Attacks&amp;quot;, RFC 6528, February 2012.&lt;br /&gt;
              Obsoletes RFC 1948.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 6582]  T. Henderson, S. Floyd, A. Gurtov, Y. Nishida,&lt;br /&gt;
              &amp;quot;The NewReno Modification to TCP&#039;s Fast Recovery&lt;br /&gt;
              Algorithm&amp;quot;, RFC 6582, April 2012.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 7323]  D. Borman, B. Braden, V. Jacobson,&lt;br /&gt;
              R. Scheffenegger (ed.), &amp;quot;TCP Extensions for High&lt;br /&gt;
              Performance&amp;quot;, RFC 7323, September 2014.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 7675]  M. Perumal, D. Wing, R. Ravindranath, T. Reddy,&lt;br /&gt;
              M. Thomson, &amp;quot;Session Traversal Utilities for NAT&lt;br /&gt;
              (STUN) Usage for Consent Freshness&amp;quot;, RFC 7675,&lt;br /&gt;
              October 2015.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8174]  B. Leiba, &amp;quot;Ambiguity of Uppercase vs Lowercase in&lt;br /&gt;
              RFC 2119 Key Words&amp;quot;, BCP 14, RFC 8174, May 2017.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8200]  S. Deering, R. Hinden, &amp;quot;Internet Protocol,&lt;br /&gt;
              Version 6 (IPv6) Specification&amp;quot;, STD 86, RFC 8200,&lt;br /&gt;
              July 2017.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8439]  Y. Nir, A. Langley, &amp;quot;ChaCha20 and Poly1305 for IETF&lt;br /&gt;
              Protocols&amp;quot;, RFC 8439, June 2018.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8446]  E. Rescorla, &amp;quot;The Transport Layer Security (TLS)&lt;br /&gt;
              Protocol Version 1.3&amp;quot;, RFC 8446, August 2018.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 8985]  Y. Cheng, N. Cardwell, N. Dukkipati, P. Jha,&lt;br /&gt;
              &amp;quot;The RACK-TLP Loss Detection Algorithm for TCP&amp;quot;,&lt;br /&gt;
              RFC 8985, February 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9000]  J. Iyengar (ed.), M. Thomson (ed.), &amp;quot;QUIC: A&lt;br /&gt;
              UDP-Based Multiplexed and Secure Transport&amp;quot;,&lt;br /&gt;
              RFC 9000, May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9001]  M. Thomson (ed.), S. Turner (ed.), &amp;quot;Using TLS to&lt;br /&gt;
              Secure QUIC&amp;quot;, RFC 9001, May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9002]  J. Iyengar (ed.), I. Swett (ed.), &amp;quot;QUIC Loss&lt;br /&gt;
              Detection and Congestion Control&amp;quot;, RFC 9002,&lt;br /&gt;
              May 2021.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9147]  E. Rescorla, H. Tschofenig, N. Modadugu,&lt;br /&gt;
              &amp;quot;The Datagram Transport Layer Security (DTLS)&lt;br /&gt;
              Protocol Version 1.3&amp;quot;, RFC 9147, April 2022.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9260]  R. Stewart, M. Tuexen, K. Nielsen, &amp;quot;Stream Control&lt;br /&gt;
              Transmission Protocol&amp;quot;, RFC 9260, June 2022.&lt;br /&gt;
              Obsoletes RFC 4960.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  [RFC 9293]  W. Eddy (ed.), &amp;quot;Transmission Control Protocol&lt;br /&gt;
              (TCP)&amp;quot;, STD 7, RFC 9293, August 2022.  Obsoletes&lt;br /&gt;
              RFC 793 and several follow-ons; updates RFC 1122&lt;br /&gt;
              and others.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.2. Books and journal papers ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - J. Day, &amp;quot;Patterns in Network Architecture: A Return to&lt;br /&gt;
    Fundamentals&amp;quot;, Prentice Hall, 2008.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - E. Grasa et al., &amp;quot;IRATI: investigating RINA as an alternative&lt;br /&gt;
    to TCP/IP&amp;quot;, Computer Networks, Vol. 92, December 2015.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - P. Karn, C. Partridge, &amp;quot;Improving Round-Trip Time Estimates&lt;br /&gt;
    in Reliable Transport Protocols&amp;quot;, ACM SIGCOMM, August 1987.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - R. W. Watson, &amp;quot;Timer-Based Mechanisms in Reliable Transport&lt;br /&gt;
    Protocol Connection Management&amp;quot;, Computer Networks, Vol. 5,&lt;br /&gt;
    1981.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 17.3. Source-code references ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  - tcp_rtt_estimator() in net/ipv4/tcp_input.c of the Linux&lt;br /&gt;
    kernel, defining the asymmetric mdev variance update used as&lt;br /&gt;
    FRCP&#039;s default RTT estimator (Section 12).  Line-stable&lt;br /&gt;
    browseable copy at&lt;br /&gt;
    https://elixir.bootlin.com/linux/latest/source/net/ipv4/tcp_input.c.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1910</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1910"/>
		<updated>2026-02-22T16:59:51Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 (Current version, February 22, 2026) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 (Current version, February 22, 2026) ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including ML-KEM, Hybrid ECDH-KEM key exchange and ML-DSA and SLH-DSA based authentication.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints based on lowest-floor exchange.&lt;br /&gt;
* Replaced the rdrbuff with per-user and priviliged shared slab allocator pools for shared memory packet buffers.&lt;br /&gt;
* Added automatic key rotation for encrypted flows.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules, plus new targets for coverage reports and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1909</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1909"/>
		<updated>2026-02-22T16:59:07Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 (Current version, February 22, 2026) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 (Current version, February 22, 2026) ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including ML-KEM, Hybrid ECDH-KEM key exchange and ML-DSA and SLH-DSA based authentication.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints based on lowest-floor exchange.&lt;br /&gt;
* Replaced the rdrbuff with per-user and priviliged shared slab allocator pools for shared memory packet buffers.&lt;br /&gt;
* Added automatic key rotation for encrypted flows.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules, plus new targets for coverage reports and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1908</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1908"/>
		<updated>2026-02-22T16:58:10Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 (Current version, February 22, 2026) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 (Current version, February 22, 2026) ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including ML-KEM, Hybrid ECDH-KEM key exchange and ML-DSA and SLH-DSA based authentication.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints,.&lt;br /&gt;
* Replaced the rdrbuff with per-user and priviliged shared slab allocator pools for shared memory packet buffers.&lt;br /&gt;
* Added automatic key rotation for encrypted flows.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules, plus new targets for coverage reports and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1907</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1907"/>
		<updated>2026-02-22T16:56:18Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 (Current version, February 22, 2026) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 (Current version, February 22, 2026) ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including ML-KEM, Hybrid ECDH-KEM and ML-DSA and SLH-DSA authentication.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints,.&lt;br /&gt;
* Replaced the rdrbuff with per-user and priviliged shared slab allocator pools for shared memory packet buffers.&lt;br /&gt;
* Added automatic key rotation for encrypted flows.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules, plus new targets for coverage reports and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1906</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1906"/>
		<updated>2026-02-22T16:54:11Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 (Current version, February 22, 2026) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 (Current version, February 22, 2026) ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including ML-KEM, Hybrid ECDH-KEM and ML-DSA and SLH-DSA authentication.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints, with fixes for client-side encryption requests.&lt;br /&gt;
* Replaced the rdrbuff with a proper slab allocator for shared memory packet buffers, a significant data-plane redesign.&lt;br /&gt;
* Added automatic key rotation for encrypted flows, with related fixes for IV/tag allocation and speedup of key rotation tests.&lt;br /&gt;
* Introduced per-user shared memory packet pools, improving multi-user isolation. Also added mlock() on shared memory buffers.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules back to in-tree CMakeLists, plus new targets for coverage reports, build_tests, and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1905</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1905"/>
		<updated>2026-02-22T16:53:49Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 (Current version, February 22, 2026) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 (Current version, February 22, 2026) ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including ML-KEM, Hybrid ECDH-KEM and ML-DSA and SLH-DSA.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints, with fixes for client-side encryption requests.&lt;br /&gt;
* Replaced the rdrbuff with a proper slab allocator for shared memory packet buffers, a significant data-plane redesign.&lt;br /&gt;
* Added automatic key rotation for encrypted flows, with related fixes for IV/tag allocation and speedup of key rotation tests.&lt;br /&gt;
* Introduced per-user shared memory packet pools, improving multi-user isolation. Also added mlock() on shared memory buffers.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules back to in-tree CMakeLists, plus new targets for coverage reports, build_tests, and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1904</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1904"/>
		<updated>2026-02-22T16:52:57Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 (Current version, February 22, 2026) ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including SLH-DSA tests and per-algorithm gating, and PQC-aware config loading in IRMd.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints, with fixes for client-side encryption requests.&lt;br /&gt;
* Replaced the rdrbuff with a proper slab allocator for shared memory packet buffers, a significant data-plane redesign.&lt;br /&gt;
* Added automatic key rotation for encrypted flows, with related fixes for IV/tag allocation and speedup of key rotation tests.&lt;br /&gt;
* Introduced per-user shared memory packet pools, improving multi-user isolation. Also added mlock() on shared memory buffers.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules back to in-tree CMakeLists, plus new targets for coverage reports, build_tests, and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1903</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1903"/>
		<updated>2026-02-22T16:52:31Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.22 (Current version, November 7th 2025) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including SLH-DSA tests and per-algorithm gating, and PQC-aware config loading in IRMd.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints, with fixes for client-side encryption requests.&lt;br /&gt;
* Replaced the rdrbuff with a proper slab allocator for shared memory packet buffers, a significant data-plane redesign.&lt;br /&gt;
* Added automatic key rotation for encrypted flows, with related fixes for IV/tag allocation and speedup of key rotation tests.&lt;br /&gt;
* Introduced per-user shared memory packet pools, improving multi-user isolation. Also added mlock() on shared memory buffers.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules back to in-tree CMakeLists, plus new targets for coverage reports, build_tests, and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1902</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1902"/>
		<updated>2026-02-22T16:52:13Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 ==&lt;br /&gt;
&lt;br /&gt;
* Added PQC support to the library, including SLH-DSA tests and per-algorithm gating, and PQC-aware config loading in IRMd.&lt;br /&gt;
* IRMd now negotiates encryption strength between endpoints, with fixes for client-side encryption requests.&lt;br /&gt;
* Replaced the rdrbuff with a proper slab allocator for shared memory packet buffers, a significant data-plane redesign.&lt;br /&gt;
* Added automatic key rotation for encrypted flows, with related fixes for IV/tag allocation and speedup of key rotation tests.&lt;br /&gt;
* Introduced per-user shared memory packet pools, improving multi-user isolation. Also added mlock() on shared memory buffers.&lt;br /&gt;
* Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* Major refactoring of CMake modules back to in-tree CMakeLists, plus new targets for coverage reports, build_tests, and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 (Current version, November 7th 2025) ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1901</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1901"/>
		<updated>2026-02-22T16:51:29Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 ==&lt;br /&gt;
&lt;br /&gt;
* Post-quantum cryptography support — Added PQC support to the library, including SLH-DSA tests and per-algorithm gating, and PQC-aware config loading in IRMd.&lt;br /&gt;
* Strength-based crypto negotiation — IRMd now negotiates encryption strength between endpoints, with fixes for client-side encryption requests.&lt;br /&gt;
* Slab allocator replacing rdrbuff — Replaced the rdrbuff with a proper slab allocator for shared memory packet buffers, a significant data-plane redesign.&lt;br /&gt;
* Automatic key rotation for encryption — Added automatic key rotation for encrypted flows, with related fixes for IV/tag allocation and speedup of key rotation tests.&lt;br /&gt;
* Per-user packet pools — Introduced per-user shared memory packet pools, improving multi-user isolation. Also added mlock() on shared memory buffers.&lt;br /&gt;
* rbuff refactoring — Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
* Direct rbuff between local processes — IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
* CMake build system overhaul — Major refactoring of CMake modules back to in-tree CMakeLists, plus new targets for coverage reports, build_tests, and automatic version parsing from git tags.&lt;br /&gt;
&lt;br /&gt;
== 0.22 (Current version, November 7th 2025) ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1900</id>
		<title>Prototype Version History</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Prototype_Version_History&amp;diff=1900"/>
		<updated>2026-02-22T16:49:17Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* 0.23 (Current development branch) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ouroboros is still in an early proof-of-concept prototype phase. Versions 0.x.y have no forward nor backward compatibility. We bump minor version with API or protocol changes. Within a minor version, different patch levels &#039;&#039;should&#039;&#039; be compatible (no guarantees).&lt;br /&gt;
&lt;br /&gt;
Once the functionality has reached a minimal critical mass, and a sufficient degree of software stability has been achieved, a version 1.0.0 will be released with the intention to maintain backwards compatibility from that point. This is still many (man)years off.&lt;br /&gt;
&lt;br /&gt;
This page summarizes the progress and the plans for the next prototype (minor) version. For a summary of the current implementation state, see [[Ouroboros Implementation Overview| our status page]].&lt;br /&gt;
&lt;br /&gt;
== 0.24 (Current development branch) ==&lt;br /&gt;
&lt;br /&gt;
== 0.23 ==&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Post-quantum cryptography support&#039;&#039;&#039; — Added PQC support to the library, including SLH-DSA tests and per-algorithm gating, and PQC-aware config loading in IRMd.&lt;br /&gt;
# &#039;&#039;&#039;Slab allocator replacing rdrbuff&#039;&#039;&#039; — Replaced the rdrbuff with a proper slab allocator for shared memory packet buffers, a significant data-plane redesign.&lt;br /&gt;
# &#039;&#039;&#039;Automatic key rotation for encryption&#039;&#039;&#039; — Added automatic key rotation for encrypted flows, with related fixes for IV/tag allocation and speedup of key rotation tests.&lt;br /&gt;
# &#039;&#039;&#039;Strength-based crypto negotiation&#039;&#039;&#039; — IRMd now negotiates encryption strength between endpoints, with fixes for client-side encryption requests.&lt;br /&gt;
# &#039;&#039;&#039;Per-user packet pools&#039;&#039;&#039; — Introduced per-user shared memory packet pools, improving multi-user isolation. Also added mlock() on shared memory buffers.&lt;br /&gt;
# &#039;&#039;&#039;Rbuff refactoring&#039;&#039;&#039; — Refactored the ring buffer implementation and removed the old &amp;quot;lockless&amp;quot; rbuff_ll variant.&lt;br /&gt;
# &#039;&#039;&#039;Direct rbuff between local processes&#039;&#039;&#039; — IRMd now allows direct ring buffer connections between local processes, reducing overhead for same-machine IPC.&lt;br /&gt;
# &#039;&#039;&#039;Linked list with length tracking&#039;&#039;&#039; — Added struct llist to the library, providing list operations that also track element count.&lt;br /&gt;
# &#039;&#039;&#039;CMake build system overhaul&#039;&#039;&#039; — Major refactoring of CMake modules back to in-tree CMakeLists, plus new targets for coverage reports, build_tests, and automatic version parsing from git tags.&lt;br /&gt;
# &#039;&#039;&#039;Container compatibility &amp;amp; OS X fixes&#039;&#039;&#039; — Added a container compatibility build option, and fixed SSM pool creation, OpenSSL includes, and explicit_bzero on OS X.&lt;br /&gt;
&lt;br /&gt;
== 0.22 (Current version, November 7th 2025) ==&lt;br /&gt;
* Added flow authentication and the Flow Allocation Protocol header in the irmd&lt;br /&gt;
* Added UDP/IPv6 support&lt;br /&gt;
* Added protocol level debug logging&lt;br /&gt;
* Moved encryption control from qosspec to naming system&lt;br /&gt;
* Removed qosspec parameter from the broadcast API&lt;br /&gt;
* Refactored and simplified enrolment and connection manager&lt;br /&gt;
* Complete rewrite of the DHT for the unicast layer&lt;br /&gt;
* Refactored Ethernet IPCPs&lt;br /&gt;
* Deprecated appveyor in favor of codeberg/woodpecker CI&lt;br /&gt;
* Improved test coverage&lt;br /&gt;
* Improved systemd service and pkgconfig installation logic&lt;br /&gt;
* Improved ctest integration into build system&lt;br /&gt;
&lt;br /&gt;
== 0.21 ==&lt;br /&gt;
* Moved public key handling from library to IRMd&lt;br /&gt;
* Refactor of IRMd / registry implementation&lt;br /&gt;
&lt;br /&gt;
== 0.20 ==&lt;br /&gt;
* Improved configuration file handling&lt;br /&gt;
* Improved FUSE stability&lt;br /&gt;
* Log unique IDs to enrollment requests&lt;br /&gt;
* Print logo on startup when logging to std output&lt;br /&gt;
* Fix most common hangs on exit&lt;br /&gt;
&lt;br /&gt;
== 0.19 ==&lt;br /&gt;
* Pass the N-1 layer MPL at flow allocation&lt;br /&gt;
* Add flow liveness monitoring.&lt;br /&gt;
* Allow multiple directories in an IPCP &lt;br /&gt;
* Dropped support for raptor&lt;br /&gt;
* Use one UDP port for the IPCP over UDP/IPv4&lt;br /&gt;
&lt;br /&gt;
== 0.18 ==&lt;br /&gt;
* Use QoS cube for ECN marking&lt;br /&gt;
* Always use 64-bit endpoint IDs&lt;br /&gt;
* Add RIB statistics for flow allocator&lt;br /&gt;
* Add congestion avoidance policies&lt;br /&gt;
* Add flow control policies&lt;br /&gt;
* Add GCC 10 static analyzer build option&lt;br /&gt;
&lt;br /&gt;
== 0.17 ==&lt;br /&gt;
* Rename systemd service to ouroboros&lt;br /&gt;
* Add tests for LFA and ECMP routing&lt;br /&gt;
* Add Equal-Cost Multi-Path routing policy&lt;br /&gt;
&lt;br /&gt;
== 0.16 ==&lt;br /&gt;
* Removed support for SWIG bindings&lt;br /&gt;
* Add support for appveyor CI&lt;br /&gt;
* Add encryption support using OpenSSL&lt;br /&gt;
&lt;br /&gt;
== 0.15 ==&lt;br /&gt;
* Rename normal IPCP to unicast IPCP&lt;br /&gt;
* Add flow_join API for broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.14 ==&lt;br /&gt;
* Add Explicit Congestion Notification field to DT&lt;br /&gt;
* Add broadcast IPCP&lt;br /&gt;
&lt;br /&gt;
== 0.13 ==&lt;br /&gt;
* Disable CRC32 by default&lt;br /&gt;
&lt;br /&gt;
== 0.12 ==&lt;br /&gt;
* Split error checking from FRCT&lt;br /&gt;
* Rename port_id to flow_id&lt;br /&gt;
* Rename SDU to packet&lt;br /&gt;
* Pass QoS spec at flow allocation&lt;br /&gt;
* Initial retransmission logic&lt;br /&gt;
* Support QoS specs for oping&lt;br /&gt;
* Use Endpoint ID&#039;s in fa protocol instead of fd&lt;br /&gt;
&lt;br /&gt;
== 0.11 ==&lt;br /&gt;
* Simplify reg/unreg API&lt;br /&gt;
* Support for partial packet reads&lt;br /&gt;
* Add IPCP over Ethernet DIX&lt;br /&gt;
&lt;br /&gt;
== 0.10 ==&lt;br /&gt;
* Revise lookup tracking in DHT&lt;br /&gt;
* Update man pages to CC-BY 4.0&lt;br /&gt;
&lt;br /&gt;
== 0.9 ==&lt;br /&gt;
* Add patchlevels for future versions&lt;br /&gt;
* Add support for Raptor FPGA Layer-1 PoC&lt;br /&gt;
&lt;br /&gt;
== 0.8 ==&lt;br /&gt;
* Use &amp;quot;program&amp;quot; instead of &amp;quot;application process&amp;quot;&lt;br /&gt;
* Use &amp;quot;process&amp;quot; instead of &amp;quot;application process instance&amp;quot;&lt;br /&gt;
* Send timestamp in oping&lt;br /&gt;
* Use 3-clause BSD license for tools&lt;br /&gt;
&lt;br /&gt;
== 0.7 ==&lt;br /&gt;
* Use ELF sections to init/fini ouroboros&lt;br /&gt;
* Simplify PFT for LFA routing&lt;br /&gt;
* Add RIB to expose metrics via FUSE&lt;br /&gt;
* Deprecate Common Distribution Application Protocol (CDAP)&lt;br /&gt;
* Simplify enroll API&lt;br /&gt;
* Deprecate Graph Adjancency Manager component&lt;br /&gt;
&lt;br /&gt;
== 0.6 ==&lt;br /&gt;
* Added a threadpool manager for improved concurrency&lt;br /&gt;
* Added Loop-Free Alternates (LFA) routing&lt;br /&gt;
* Add DHT as default directory policy&lt;br /&gt;
&lt;br /&gt;
== 0.5 ==&lt;br /&gt;
* Move FRCT logic from IPCP to application library&lt;br /&gt;
* Split connection establishment from flow allocation&lt;br /&gt;
* Split flow manager into flow allocator and data transfer&lt;br /&gt;
* Register hashes in a layer instead of cleartext name&lt;br /&gt;
* Add netmap support for LLC shim&lt;br /&gt;
* Initial lockless rbuff implementation&lt;br /&gt;
* Add generic thread pool management&lt;br /&gt;
* Revise flow allocation API&lt;br /&gt;
* Split authentication from CACEP&lt;br /&gt;
* Revise CACEP API&lt;br /&gt;
* Exchange application protocol information during CACEP&lt;br /&gt;
&lt;br /&gt;
== 0.4 ==&lt;br /&gt;
* Add support for syslog logging&lt;br /&gt;
* Revise RIB/CDAP as a btree structure&lt;br /&gt;
* Add B-tree implementation&lt;br /&gt;
* Add full-mesh policy for GAM&lt;br /&gt;
* Add Graph Adjacency Manager (GAM)&lt;br /&gt;
* Add flat address policy&lt;br /&gt;
* Add initial directory to normal IPCP&lt;br /&gt;
* Initial RIB/CDAP synchronization&lt;br /&gt;
* Add RIB/CDAP objects&lt;br /&gt;
* Add operf tool&lt;br /&gt;
&lt;br /&gt;
== 0.3 ==&lt;br /&gt;
* Move all shared memory (shm) mgmt to IRMd&lt;br /&gt;
* Use shared memory tx/rx ring buffer per flow&lt;br /&gt;
* Split off bind/unbind (map/unmap name to process) from reg/unreg&lt;br /&gt;
&lt;br /&gt;
== 0.2 ==&lt;br /&gt;
* Add shim DIF over LLC Ethernet&lt;br /&gt;
* Add CBR tool for performance testing&lt;br /&gt;
* Add IPCP over local memory&lt;br /&gt;
&lt;br /&gt;
== 0.1 ==&lt;br /&gt;
* Add full flow allocator to UDP shim&lt;br /&gt;
* Implementation of flow related ops&lt;br /&gt;
* Simple echo application&lt;br /&gt;
* Initial shim IPCP over UDP/IPv4&lt;br /&gt;
* Add RINA name helpers&lt;br /&gt;
* Initial library code&lt;br /&gt;
* Initial SDU/PDU buffer code&lt;br /&gt;
* Initial APIs for IRM/IPCP/CFAP/DIF allocator&lt;br /&gt;
* Initial CDAP header&lt;br /&gt;
* LICENSE and CONTRIBUTORS files&lt;br /&gt;
* Initial documenents and GPLv2 license&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1899</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1899"/>
		<updated>2026-02-14T15:16:19Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 1: No Authentication, No Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured (except for the request hash in the response). Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated ephemeral prime256v1 keys (91 bytes).&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] No crt provided.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client cipher aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client KDF sha256.&lt;br /&gt;
irmd/oap(II): [80fd6f9509a996b0] No key exchange.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated prime256v1 ephemeral keys.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] &amp;lt;--&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [03e47baa966a5823 @ 2026-02-14 14:09:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [03e47baa966a5823 @ 2026-02-14 14:09:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1898</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1898"/>
		<updated>2026-02-14T15:15:44Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 2: No Authentication, With Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [60e824383b3fbd6a] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured (except for the request hash in the response). Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated ephemeral prime256v1 keys (91 bytes).&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] No crt provided.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client cipher aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client KDF sha256.&lt;br /&gt;
irmd/oap(II): [80fd6f9509a996b0] No key exchange.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated prime256v1 ephemeral keys.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] &amp;lt;--&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [03e47baa966a5823 @ 2026-02-14 14:09:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [03e47baa966a5823 @ 2026-02-14 14:09:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1897</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1897"/>
		<updated>2026-02-14T15:14:50Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 4: With Authentication, No Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [60e824383b3fbd6a] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured (except for the request hash in the response). Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] KEX config: algo=prime256v1, mode=server-encap, cipher=aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated ephemeral prime256v1 keys (91 bytes).&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] No crt provided.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client cipher aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client KDF sha256.&lt;br /&gt;
irmd/oap(II): [80fd6f9509a996b0] No key exchange.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated prime256v1 ephemeral keys.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] &amp;lt;--&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [03e47baa966a5823 @ 2026-02-14 14:09:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [03e47baa966a5823 @ 2026-02-14 14:09:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1896</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1896"/>
		<updated>2026-02-14T14:59:54Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 4: With Authentication, No Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [60e824383b3fbd6a] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured (except for the request hash in the response). Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] KEX config: algo=prime256v1, mode=server-encap, cipher=aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated ephemeral prime256v1 keys (91 bytes).&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] No crt provided.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client cipher aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client KDF sha256.&lt;br /&gt;
irmd/oap(II): [80fd6f9509a996b0] No key exchange.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated prime256v1 ephemeral keys.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] &amp;lt;--&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [03e47baa966a5823 @ 2026-02-14 14:09:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [03e47baa966a5823 @ 2026-02-14 14:09:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [03e47baa966a5823] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1895</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1895"/>
		<updated>2026-02-14T14:56:42Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 3: With Authentication, With Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [60e824383b3fbd6a] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured (except for the request hash in the response). Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] KEX config: algo=prime256v1, mode=server-encap, cipher=aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated ephemeral prime256v1 keys (91 bytes).&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] No crt provided.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client cipher aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client KDF sha256.&lt;br /&gt;
irmd/oap(II): [80fd6f9509a996b0] No key exchange.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated prime256v1 ephemeral keys.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] &amp;lt;--&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [c904b18b563dc1b0 @ 2026-02-14 14:09:47 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: [560 bytes]&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Loaded peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Got public key from crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully verified peer crt.&lt;br /&gt;
irmd/oap(DB): [c904b18b563dc1b0] Successfully authenticated peer.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33642 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf does not exist.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211 @ 2026-01-01 11:27:34 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1894</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1894"/>
		<updated>2026-02-14T14:51:49Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 2: No Authentication, With Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [60e824383b3fbd6a] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured (except for the request hash in the response). Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] KEX config: algo=prime256v1, mode=server-encap, cipher=aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated ephemeral prime256v1 keys (91 bytes).&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] No crt provided.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client cipher aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Selected client KDF sha256.&lt;br /&gt;
irmd/oap(II): [80fd6f9509a996b0] No key exchange.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated prime256v1 ephemeral keys.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [32 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33500 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33500.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3f89a905c0e5571b @ 2026-01-01 11:27:25 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33198.&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3f89a905c0e5571b] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33642 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf does not exist.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211 @ 2026-01-01 11:27:34 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1893</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1893"/>
		<updated>2026-02-14T14:49:28Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 2: No Authentication, With Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [60e824383b3fbd6a] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured (except for the request hash in the response). Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] KEX config: algo=prime256v1, mode=server-encap, cipher=aes-256-gcm.&lt;br /&gt;
irmd/oap(DB): [80fd6f9509a996b0] Generated ephemeral prime256v1 keys (91 bytes).&lt;br /&gt;
irmd/oap(PP): OAP_HDR [80fd6f9509a996b0 @ 2026-02-14 14:09:38 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Key Exchange Data: [91 bytes] [Server encaps]&lt;br /&gt;
irmd/oap(PP):   Cipher: aes-256-gcm&lt;br /&gt;
irmd/oap(PP):   KDF: HKDF-sha256&lt;br /&gt;
irmd/oap(PP):   Digest: sha256&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33198.&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3fa5ac1a91a23936] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by sec.oping.tut.o7s.&lt;br /&gt;
==33047== reg/name(DB): Process 33198 accepting flows for sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33500 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33500.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3f89a905c0e5571b @ 2026-01-01 11:27:25 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33198.&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3f89a905c0e5571b] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33642 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf does not exist.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211 @ 2026-01-01 11:27:34 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1892</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1892"/>
		<updated>2026-02-14T14:46:17Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 1: No Authentication, No Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [60e824383b3fbd6a] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:57 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: [48 bytes]&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured (except for the request hash in the response). Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33356 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33356.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3fa5ac1a91a23936 @ 2026-01-01 11:27:15 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33198.&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3fa5ac1a91a23936] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by sec.oping.tut.o7s.&lt;br /&gt;
==33047== reg/name(DB): Process 33198 accepting flows for sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33500 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33500.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3f89a905c0e5571b @ 2026-01-01 11:27:25 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33198.&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3f89a905c0e5571b] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33642 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf does not exist.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211 @ 2026-01-01 11:27:34 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1891</id>
		<title>Ouroboros Tutorial 06</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Tutorial_06&amp;diff=1891"/>
		<updated>2026-02-14T14:42:30Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Test 1: No Authentication, No Encryption */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Ouroboros Tutorial 06 - Authenticated Flows =&lt;br /&gt;
&lt;br /&gt;
This tutorial demonstrates setting up and using authenticated flows in Ouroboros with certificate-based authentication.&lt;br /&gt;
&lt;br /&gt;
The overall flow of authenticated flow allocation is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tutorial Directory:&#039;&#039;&#039; This tutorial will execute in &amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;. All configuration files, generated certificates, logs, and packet captures will be stored in this directory.&lt;br /&gt;
&lt;br /&gt;
We create a complete PKI (Public Key Infrastructure):&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Root CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;ca.tut.o7s&amp;lt;/code&amp;gt;): Self-signed trust anchor&lt;br /&gt;
* &#039;&#039;&#039;Intermediate CA&#039;&#039;&#039; (&amp;lt;code&amp;gt;sign.tut.o7s&amp;lt;/code&amp;gt;): Signed by root with pathlen:0 constraint&lt;br /&gt;
* &#039;&#039;&#039;Server Certificate&#039;&#039;&#039; (&amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;): Signed by intermediate CA&lt;br /&gt;
&lt;br /&gt;
This tutorial uses ECDSA P-384 with SHA-384 hashing.&lt;br /&gt;
&lt;br /&gt;
== Setting Up the Tutorial ==&lt;br /&gt;
&lt;br /&gt;
To properly understand and debug the authenticated flows, this tutorial uses a debug build of Ouroboros with OAP protocol debugging enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /path/to/ouroboros&lt;br /&gt;
mkdir build &amp;amp;&amp;amp; cd build&lt;br /&gt;
cmake -DCMAKE_BUILD_TYPE=Debug -DDEBUG_PROTO_OAP=ON ..&lt;br /&gt;
make -j$(nproc)&lt;br /&gt;
sudo make install&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When built with these options, the IRMd will output detailed OAP protocol information.&lt;br /&gt;
&lt;br /&gt;
=== Configuration Files ===&lt;br /&gt;
&lt;br /&gt;
The following three files should be created in the tutorial directory (&amp;lt;code&amp;gt;/tmp/o7s-tut06/&amp;lt;/code&amp;gt;) before starting the tutorial:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tut06.conf&#039;&#039;&#039; - IRMd configuration&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
# Ouroboros Tutorial 06 - Authenticated Flows Configuration&lt;br /&gt;
# Uses system-installed certificates at /etc/ouroboros/security/&lt;br /&gt;
&lt;br /&gt;
[name.&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
prog=[&amp;quot;/usr/bin/oping&amp;quot;]&lt;br /&gt;
args=[&amp;quot;--listen&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
[eth-dix.eth-dix-lo]&lt;br /&gt;
bootstrap=&amp;quot;eth-dix-network&amp;quot;&lt;br /&gt;
dev=&amp;quot;lo&amp;quot;&lt;br /&gt;
reg=[&amp;quot;sec.oping.tut.o7s&amp;quot;]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ca.tut.o7s.cnf&#039;&#039;&#039; - OpenSSL configuration for PKI generation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# Unified OpenSSL Configuration for Ouroboros Tutorial 06&lt;br /&gt;
# Named CA sections: CA_root (signs intermediate), CA_intermediate (signs server)&lt;br /&gt;
# Usage: openssl ca -name CA_root -config ca.tut.o7s.cnf ...&lt;br /&gt;
&lt;br /&gt;
[ req ]&lt;br /&gt;
default_bits       = 384&lt;br /&gt;
default_keyfile    = private/key.pem&lt;br /&gt;
distinguished_name = req_distinguished_name&lt;br /&gt;
string_mask        = utf8only&lt;br /&gt;
default_md         = sha384&lt;br /&gt;
x509_extensions    = v3_ca&lt;br /&gt;
&lt;br /&gt;
[ req_distinguished_name ]&lt;br /&gt;
countryName                 = Country Name (2 letter code)&lt;br /&gt;
stateOrProvinceName         = State or Province Name&lt;br /&gt;
localityName                = Locality Name&lt;br /&gt;
organizationName            = Organization Name&lt;br /&gt;
commonName                  = Common Name&lt;br /&gt;
&lt;br /&gt;
countryName_default         = BE&lt;br /&gt;
stateOrProvinceName_default = OVL&lt;br /&gt;
localityName_default        = Ghent&lt;br /&gt;
organizationName_default    = o7s&lt;br /&gt;
&lt;br /&gt;
[ ca ]&lt;br /&gt;
default_ca = CA_root&lt;br /&gt;
&lt;br /&gt;
[ CA_root ]&lt;br /&gt;
dir             = ./pki/root&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/ca.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/ca.tut.o7s.key.pem&lt;br /&gt;
default_days    = 3650&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ CA_intermediate ]&lt;br /&gt;
dir             = ./pki/sign&lt;br /&gt;
database        = $dir/index.txt&lt;br /&gt;
serial          = $dir/serial&lt;br /&gt;
new_certs_dir   = $dir/certs&lt;br /&gt;
certificate     = $dir/certs/sign.tut.o7s.crt.pem&lt;br /&gt;
private_key     = $dir/private/sign.tut.o7s.key.pem&lt;br /&gt;
default_days    = 365&lt;br /&gt;
default_md      = sha384&lt;br /&gt;
policy          = policy_loose&lt;br /&gt;
&lt;br /&gt;
[ policy_loose ]&lt;br /&gt;
commonName = supplied&lt;br /&gt;
&lt;br /&gt;
[ v3_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ v3_intermediate_ca ]&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid:always,issuer&lt;br /&gt;
basicConstraints = critical, CA:true, pathlen:0&lt;br /&gt;
keyUsage = critical, digitalSignature, cRLSign, keyCertSign&lt;br /&gt;
&lt;br /&gt;
[ server_cert ]&lt;br /&gt;
basicConstraints = CA:FALSE&lt;br /&gt;
subjectKeyIdentifier = hash&lt;br /&gt;
authorityKeyIdentifier = keyid,issuer:always&lt;br /&gt;
keyUsage = critical, digitalSignature, keyEncipherment&lt;br /&gt;
extendedKeyUsage = serverAuth&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gen-pki.sh&#039;&#039;&#039; - PKI generation script&lt;br /&gt;
&lt;br /&gt;
This script will:&lt;br /&gt;
1. Create the directory structure&lt;br /&gt;
2. Generate the root CA key and certificate&lt;br /&gt;
3. Generate the intermediate CA key and CSR&lt;br /&gt;
4. Sign the intermediate CA certificate&lt;br /&gt;
5. Generate the server certificate key and CSR&lt;br /&gt;
6. Sign the server certificate&lt;br /&gt;
7. Verify the complete certificate chain&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
# Ouroboros Tutorial 06 - PKI Generation Script (Simplified)&lt;br /&gt;
# Generates: Root CA, Intermediate CA, and Server Certificate&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
if [ ! -f ca.tut.o7s.cnf ]; then&lt;br /&gt;
    echo &amp;quot;ERROR: ca.tut.o7s.cnf not found&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
mkdir -p pki/{root,sign,server}/{certs,private,csr}&lt;br /&gt;
&lt;br /&gt;
# Root CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/root/private/ca.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -x509 -sha384 -days 7300 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/root/private/ca.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=ca.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
# Intermediate CA&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/sign/private/sign.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/sign/private/sign.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sign.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/root/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/root/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_root -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions v3_intermediate_ca -days 3650 -md sha384 -batch \&lt;br /&gt;
    -in pki/sign/csr/sign.tut.o7s.csr \&lt;br /&gt;
    -out pki/sign/certs/sign.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Server Certificate&lt;br /&gt;
openssl ecparam -genkey -name secp384r1 -out pki/server/private/sec.oping.tut.o7s.key.pem 2&amp;gt;/dev/null&lt;br /&gt;
openssl req -new -sha384 \&lt;br /&gt;
    -config ca.tut.o7s.cnf \&lt;br /&gt;
    -key pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
    -out pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -subj &amp;quot;/C=BE/ST=OVL/L=Ghent/O=o7s/CN=sec.oping.tut.o7s&amp;quot; 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
touch pki/sign/index.txt&lt;br /&gt;
echo 1000 &amp;gt; pki/sign/serial&lt;br /&gt;
&lt;br /&gt;
openssl ca -name CA_intermediate -config ca.tut.o7s.cnf \&lt;br /&gt;
    -extensions server_cert -days 365 -md sha384 -batch \&lt;br /&gt;
    -in pki/server/csr/sec.oping.tut.o7s.csr \&lt;br /&gt;
    -out pki/server/certs/sec.oping.tut.o7s.crt.pem 2&amp;gt;&amp;amp;1 | grep -E &amp;quot;Signature ok|Database updated&amp;quot; || true&lt;br /&gt;
&lt;br /&gt;
# Verify chain&lt;br /&gt;
openssl verify -CAfile pki/root/certs/ca.tut.o7s.crt.pem \&lt;br /&gt;
    -untrusted pki/sign/certs/sign.tut.o7s.crt.pem \&lt;br /&gt;
    pki/server/certs/sec.oping.tut.o7s.crt.pem &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;PKI generation complete.&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 1: Running the Tutorial - Single Session with 4 Tests ==&lt;br /&gt;
&lt;br /&gt;
This section demonstrates a single continuous session with one IRMd and tcpdump instance. The configuration file (&amp;lt;code&amp;gt;tut06.conf&amp;lt;/code&amp;gt;) includes autostart for oping, so the server is ready immediately when IRMd starts.&lt;br /&gt;
&lt;br /&gt;
First install the &#039;&#039;&#039;CA and Intermediate CA only&#039;&#039;&#039; to the system security directories. The server certificate will be installed later during Test 3 (authentication test):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo mkdir -p /etc/ouroboros/security/{cacert,untrusted,server/sec.oping.tut.o7s,client/sec.oping.tut.o7s}&lt;br /&gt;
&lt;br /&gt;
# Run the PKI generation script&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo chmod +x gen-pki.sh&lt;br /&gt;
sudo ./gen-pki.sh&lt;br /&gt;
&lt;br /&gt;
# Install Root CA (trust anchor)&lt;br /&gt;
sudo cp pki/root/certs/ca.tut.o7s.crt.pem /etc/ouroboros/security/cacert/&lt;br /&gt;
&lt;br /&gt;
# Install Intermediate CA (for certificate chain validation)&lt;br /&gt;
sudo cp pki/sign/certs/sign.tut.o7s.crt.pem /etc/ouroboros/security/untrusted/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Running the Tutorial (3 Terminals) ===&lt;br /&gt;
&lt;br /&gt;
In this tutorial, we run a single IRMd session with a concurrent tcpdump instance to capture it. We then run four oping client tests while the IRMd/tcpdump sessions are going, modifying the security configuration between tests. After the tests are complete, we can will down the IRMd and tcpdump sessions with Ctrl-C.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 1: Start tcpdump to capture all packets (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -i lo -n -A -v -U -w /tmp/o7s-tut06/tut06.pcap &amp;quot;ether proto 0xa000&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 2: Start IRMd with debug output (runs continuously)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /tmp/o7s-tut06&lt;br /&gt;
sudo irmd --config tut06.conf --stdout 2&amp;gt;&amp;amp;1 | tee /tmp/o7s-tut06/irmd.log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Terminal 3: Run the tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Test 1: No Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Verify directories are empty&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/client/sec.oping.tut.o7s/*&lt;br /&gt;
sudo ls -la /etc/ouroboros/security/server/sec.oping.tut.o7s/*&lt;br /&gt;
&lt;br /&gt;
# Run first ping test&lt;br /&gt;
echo &amp;quot;=== Test 1: No Authentication, No Encryption ===&amp;quot;&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Client initiates plaintext flow allocation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
irmd/oap(DB): [60e824383b3fbd6a] KEX config: algo=none, mode=server-encap, cipher=none.&lt;br /&gt;
irmd/oap(PP): OAP_HDR [60e824383b3fbd6a @ 2026-02-14 14:08:56 (UTC) ] --&amp;gt;&lt;br /&gt;
irmd/oap(PP):   crt: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Cipher: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   KDF: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Digest: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Req Hash: &amp;lt;none&amp;gt;&lt;br /&gt;
irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 1: Server accepts and completes handshake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [f1c3efe0833e2c76] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by sec.oping.tut.o7s.&lt;br /&gt;
==33047== reg/name(DB): Process 33198 accepting flows for sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; All OAP fields are &amp;lt;code&amp;gt;&amp;lt;none&amp;gt;&amp;lt;/code&amp;gt; because no security is configured. Flow succeeds with plaintext communication.&lt;br /&gt;
&lt;br /&gt;
==== Test 2: No Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Enable encryption for client only&lt;br /&gt;
sudo touch /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run second ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Client initiates flow with encryption enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33356 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33356.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3fa5ac1a91a23936 @ 2026-01-01 11:27:15 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 2: Server receives and responds with ephemeral key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33198.&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3fa5ac1a91a23936] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by sec.oping.tut.o7s.&lt;br /&gt;
==33047== reg/name(DB): Process 33198 accepting flows for sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Both client and server generate ephemeral keys (91 bytes each) for encryption. No certificates because authentication is not required. Encryption and authentication are independent.&lt;br /&gt;
&lt;br /&gt;
==== Test 3: With Authentication, With Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Install server certificates and keys&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/certs/sec.oping.tut.o7s.crt.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/crt.pem&lt;br /&gt;
sudo cp /tmp/o7s-tut06/pki/server/private/sec.oping.tut.o7s.key.pem \&lt;br /&gt;
        /etc/ouroboros/security/server/sec.oping.tut.o7s/key.pem&lt;br /&gt;
&lt;br /&gt;
# enc.conf is still in place from Test 2&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client initiates flow with encryption and server has certificate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33500 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Encryption enabled for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33500.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3f89a905c0e5571b @ 2026-01-01 11:27:25 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Server responds with certificate + ephemeral key + signature&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Generated ephemeral keys for 33198.&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [3f89a905c0e5571b] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: [91 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 3: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Full OAP handshake with certificate (560 bytes) + ephemeral keys (91 bytes) + signature (103 bytes). Client verifies server&#039;s certificate against CA store and confirms authentication success.&lt;br /&gt;
&lt;br /&gt;
==== Test 4: With Authentication, No Encryption ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Remove encryption config but keep certificates&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf&lt;br /&gt;
&lt;br /&gt;
# Run fourth ping test&lt;br /&gt;
oping -n sec.oping.tut.o7s -c 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client initiates plaintext flow (no encryption file)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): Allocating flow for 33642 to sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/enc.conf does not exist.&lt;br /&gt;
==33047== irmd(DB): File /etc/ouroboros/security/client/sec.oping.tut.o7s/crt.pem does not exist.&lt;br /&gt;
==33047== irmd(II): No security info for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211 @ 2026-01-01 11:27:34 (UTC) ] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: &amp;lt;none&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Server responds with certificate + signature (no ephemeral key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(II): No certificate provided by &amp;lt;client&amp;gt;.&lt;br /&gt;
==33047== irmd/oap(PP): OAP_HDR [9b383e855577d211] --&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Certificate: [560 bytes]&lt;br /&gt;
==33047== irmd/oap(PP):   Ephemeral Public Key: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Data: &amp;lt;none&amp;gt;&lt;br /&gt;
==33047== irmd/oap(PP):   Signature: [103 bytes]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IRMd Output - Test 4: Client verifies certificate and authenticates&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
==33047== irmd(DB): Loaded peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Certificate matches name sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(DB): Got public key from certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully verified peer certificate for sec.oping.tut.o7s.&lt;br /&gt;
==33047== irmd(II): Successfully authenticated sec.oping.tut.o7s.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039; Server sends certificate + signature for authentication, but NO ephemeral keys (plaintext data). Data exchanged without encryption even though authenticated. Demonstrates that authentication and encryption are independent mechanisms.&lt;br /&gt;
&lt;br /&gt;
=== Stop the IRMd and tcpdump, clean up the tutorial files ===&lt;br /&gt;
&lt;br /&gt;
Once all tests complete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Stop IRMd in Terminal 2 (Ctrl+C)&lt;br /&gt;
# Stop tcpdump in Terminal 1 (Ctrl+C)&lt;br /&gt;
&lt;br /&gt;
# Clean up tutorial security files from system&lt;br /&gt;
sudo rm -f /etc/ouroboros/security/cacert/ca.tut.o7s.crt.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Part 2: PCAP Trace Analysis ==&lt;br /&gt;
&lt;br /&gt;
After the tutorial, we now explain the trace in the tcpdump pcap file.&lt;br /&gt;
&lt;br /&gt;
=== Protocol Overview ===&lt;br /&gt;
&lt;br /&gt;
This section summarizes the four protocols that work together in the captured packet flow.&lt;br /&gt;
&lt;br /&gt;
==== Ethernet DIX Frame with EID Header ====&lt;br /&gt;
&lt;br /&gt;
Ouroboros extends the DIX frame with a flow identifier (EID - Endpoint Identifier) and length field.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Octets !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Destination MAC || 0-5 || 6 bytes || Hardware address of destination&lt;br /&gt;
|-&lt;br /&gt;
| Source MAC || 6-11 || 6 bytes || Hardware address of source&lt;br /&gt;
|-&lt;br /&gt;
| EtherType || 12-13 || 2 bytes || Protocol identifier (0xA000 for Ouroboros)&lt;br /&gt;
|-&lt;br /&gt;
| EID || 14-15 || 2 bytes || Destination Endpoint Identifier&lt;br /&gt;
|-&lt;br /&gt;
| Length || 16-17 || 2 bytes || Payload length (needed because of runt frame padding)&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 18+ || Variable || Frame data (up to MTU size)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ethernet Flow Allocator - Management Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ethernet DIX management protocol handles flow allocation, setup, and teardown. All management frames use destination EID &amp;lt;code&amp;gt;0x0000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Management Frame Types:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Type !! Direction !! Service Hash !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Request new flow allocation&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;FLOW_REPLY&amp;lt;/code&amp;gt; || Server → Client || – Not included || Respond to flow request (success/failure)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REQ&amp;lt;/code&amp;gt; || Client → Server || ✓ Included || Query if a remote name is reachable&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;NAME_QUERY_REPLY&amp;lt;/code&amp;gt; || Server → Client || ✓ Included || Response to name query&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; The 32-byte service hash (SHA3-256) is appended after the management protocol header for NAME_QUERY_* and FLOW_REQ messages to identify which service is being queried or allocated. FLOW_REPLY does not include the service hash; the endpoints are already identified by the allocated EIDs (SEID/DEID) and the flow allocation ID in the OAP header (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| SEID || 0-1 || 2 bytes || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| DEID || 2-3 || 2 bytes || Destination Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Loss || 4-7 || 4 bytes || Acceptable packet loss (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Bandwidth || 8-15 || 8 bytes || Required bandwidth (bps)&lt;br /&gt;
|-&lt;br /&gt;
| BER || 16-19 || 4 bytes || Bit error rate (ppm)&lt;br /&gt;
|-&lt;br /&gt;
| Max Gap || 20-23 || 4 bytes || Maximum consecutive lost packets&lt;br /&gt;
|-&lt;br /&gt;
| Delay || 24-27 || 4 bytes || Maximum latency (ms)&lt;br /&gt;
|-&lt;br /&gt;
| Timeout || 28-31 || 4 bytes || Flow idle timeout (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| Response || 32-35 || 4 bytes || Response code (0=success, negative=error)&lt;br /&gt;
|-&lt;br /&gt;
| In-Order || 36 || 1 byte || In-order delivery requirement (boolean)&lt;br /&gt;
|-&lt;br /&gt;
| Code || 37 || 1 byte || Message type (FLOW_REQ, FLOW_REPLY, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| Availability || 38 || 1 byte || Availability status&lt;br /&gt;
|-&lt;br /&gt;
| Service hash || 39-61 || 32 bytes || SHA3-256 hash (optional, see above)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Ouroboros Flow Allocation Protocol (OAP) ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Application Protocol (OAP) is the flow allocation and authentication protocol. It carries flow negotiation requests, responses, and authentication credentials. OAP frames are encapsulated as data payload over the management protocol.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| ID || 0-15 || 16 bytes || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp || 16-23 || 8 bytes || Creation timestamp (UTC, seconds and microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| Crt Length || 24-25 || 2 bytes || Certificate length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Certificate || 26+ || Variable || X.509 certificate (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Eph Length || Variable || 2 bytes || Ephemeral public key length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Ephemeral Key || Variable || Variable || ECDHE public key (DER/raw encoded)&lt;br /&gt;
|-&lt;br /&gt;
| Data Length || Variable || 2 bytes || Application data length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Data || Variable || Variable || Piggybacked application-layer data&lt;br /&gt;
|-&lt;br /&gt;
| Sig Length || Variable || 2 bytes || Signature length (bytes)&lt;br /&gt;
|-&lt;br /&gt;
| Signature || Variable || Variable || Digital signature (ECDSA, DER encoded)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Oping Application Protocol ====&lt;br /&gt;
&lt;br /&gt;
The Ouroboros Ping (oping) application is a simple echo/reply protocol used to measure round-trip time and validate connectivity between applications. It implements a request/reply pattern similar to ICMP ping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Frame Layout by Field:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Size !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Type || 0-3 || 4 bytes || Message type (ECHO_REQUEST=0 or ECHO_REPLY=1)&lt;br /&gt;
|-&lt;br /&gt;
| ID || 4-7 || 4 bytes || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (seconds) || 8-15 || 8 bytes || Seconds when message was sent (CLOCK_REALTIME)&lt;br /&gt;
|-&lt;br /&gt;
| Timestamp (nanoseconds) || 16-23 || 8 bytes || Nanoseconds component of timestamp&lt;br /&gt;
|-&lt;br /&gt;
| Payload || 24+ || Variable || Application data (configurable size, default 64 bytes)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Field Definitions:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type&#039;&#039;&#039; (4 bytes): Message type selector&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; (ECHO_REQUEST): Client-to-server ping request&lt;br /&gt;
** &amp;lt;code&amp;gt;0x00000001&amp;lt;/code&amp;gt; (ECHO_REPLY): Server-to-client response&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ID&#039;&#039;&#039; (4 bytes): Sequence number for matching requests with replies. Incremented for each ping sent.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit seconds component from when the ping was sent (CLOCK_REALTIME).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; (8 bytes): Network-byte-order 64-bit nanoseconds component (0-999999999) for high-resolution timing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Payload&#039;&#039;&#039; (Variable): Application data echoed back by the server. Size is configurable (default 64 bytes, maximum 1500 bytes).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Usage:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Client sends ECHO_REQUEST with current timestamp&lt;br /&gt;
* Server receives request and echoes back as ECHO_REPLY with the same ID and timestamps&lt;br /&gt;
* Client calculates RTT by comparing reception time with original timestamps&lt;br /&gt;
* Out-of-order detection by tracking sequence numbers (ID field)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 1 - No authentication/encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 1: NAME_QUERY_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends a NAME_QUERY_REQ message to discover if the service &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; is available. This is a broadcast discovery query sent because the service is not yet known for the flow allocation process.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.165639 00:00:00:00:00:00 &amp;gt; ff:ff:ff:ff:ff:ff, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0002 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 2: NAME_QUERY_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to the NAME_QUERY_REQ by sending a NAME_QUERY_REPLY for the service hash.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.166073 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0000 0000 0000 0000 0000 0000  ...G............&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0003 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a              ..f.i.._...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0000 || Source Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;03&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x03 || Message Type: NAME_QUERY_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt; (echoed back)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Packet 3: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates a flow allocation request (FLOW_REQ) with minimal OAP headers since no authentication or encryption is being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:48.167222 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a51 8a56 ff6f  ..f.i.._...Q.V.o&lt;br /&gt;
        0x0050:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e103  [...}....0w.....&lt;br /&gt;
        0x0060:  3e52 3300 0000 0000 0000 00              &amp;gt;R3........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || -- || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0001 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x4b (after management protocol + service hash):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e103 3e52 33&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp (seconds + microseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 (first allocated flow ID for this session)&lt;br /&gt;
* Service hash is carried in management protocol payload (32 bytes)&lt;br /&gt;
* OAP header is minimal: only ID and timestamp, no optional fields&lt;br /&gt;
* No certificate, ephemeral key, data, or signature in this initial request&lt;br /&gt;
* Client sends minimal OAP headers with no authentication or encryption setup at allocation time&lt;br /&gt;
&lt;br /&gt;
==== Packet 4: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to FLOW_REQ by sending FLOW_REPLY with a new DEID (destination endpoint ID 0x0041) to establish the allocated flow for data transfer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:49.178732 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 89:&lt;br /&gt;
        0x0000:  0000 0047 0041 0040 0000 0000 0000 0000  ...G.A.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0051 8a56 ff6f  ...........Q.V.o&lt;br /&gt;
        0x0030:  5ba6 9d03 7da1 cfc3 0f30 7718 86a8 e13f  [...}....0w....?&lt;br /&gt;
        0x0040:  a347 3800 0000 0000 0000 00              .G8........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0047&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 71 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server-side flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0|| Response code (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The OAP payload starts at offset 0x2b (no service hash in FLOW_REPLY):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;51 8a56 ff6f 5ba6 9d03 7da1 cfc3 0f30 77&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Echo of client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e13f a347 38&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || No ephemeral key&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0x48 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x49-0x4a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0041 is the newly allocated server-side flow endpoint&lt;br /&gt;
* DEID 0x0040 reflects the client&#039;s flow ID, creating a bidirectional mapping&lt;br /&gt;
* No service hash included (FLOW_REPLY only needs the EIDs to identify the flow)&lt;br /&gt;
* OAP echoes the client&#039;s ID and timestamp, confirming the flow allocation&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
* Both client and server now have their respective flow IDs (0x0040 and 0x0041) for data transfer&lt;br /&gt;
* Response code 0x00000000 indicates success&lt;br /&gt;
&lt;br /&gt;
==== Packet 5: ECHO_REQUEST - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends an oping ECHO_REQUEST packet to the server using the allocated flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.180824 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 7377 0000  .A.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (server → client)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number (first ping)&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Seconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Nanoseconds component&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (default 64 bytes total - 24 byte header = 40 bytes data)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0041 shows traffic from server-side flow ID&lt;br /&gt;
* This is the first ping request (ID = 0x00000000)&lt;br /&gt;
* Timestamp captures when the ping was sent (seconds in network order)&lt;br /&gt;
* Default oping payload is 64 bytes total; 24 bytes header + 40 bytes data&lt;br /&gt;
&lt;br /&gt;
==== Packet 6: ECHO_REPLY - Plaintext Data ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives the ECHO_REQUEST and immediately sends back an ECHO_REPLY with the same ID and timestamps, echoing the client&#039;s message.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:50.181496 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 7377 0000  .@.@........sw..&lt;br /&gt;
        0x0010:  0000 0000 b03e e007 0000 0000 0000 0000  .....&amp;gt;..........&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client ← server)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Oping payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY Payload&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The oping payload starts at offset 0x04:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;7377 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || 0x0000000000003773 || Echo of original seconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;b03e e007 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || 0x0000000007e03eb0 || Echo of original nanoseconds&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 0000 ... 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || All zeros || Echo data (unchanged from request)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows traffic from client-side flow ID receiving the reply&lt;br /&gt;
* Type field changed from 0x00000000 (REQUEST) to 0x00000001 (REPLY)&lt;br /&gt;
* ID, timestamps, and payload data are identical to the request (echoed back)&lt;br /&gt;
* Round-trip time can be calculated by comparing current time with echoed timestamp&lt;br /&gt;
* Ping succeeded on first attempt with minimal latency (~1 millisecond between timestamps)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 2 - No authentication, with encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 7: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with encryption enabled. This FLOW_REQ carries an OAP header with an ephemeral ECDHE P-384 public key (91 bytes) for encryption setup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.808158 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8af1 766b 547c  ..f.i.._....vkT|&lt;br /&gt;
        0x0050:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0060:  8b6c 9000 0000 5b30 5930 1306 072a 8648  .l....[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 c508 1c19 6106 b7e9 3074 57b9 bb16  ......a...0tW...&lt;br /&gt;
        0x0090:  6959 4a55 81f9 169b cc79 fe10 a882 41fe  iYJU.....y....A.&lt;br /&gt;
        0x00a0:  0697 c9b4 f8f0 5562 7fa2 c7a0 a020 1ac6  ......Ub........&lt;br /&gt;
        0x00b0:  939f 23ff b2fb 07a2 b747 aacc 474a 3dab  ..#......G..GJ=.&lt;br /&gt;
        0x00c0:  2598 0000 0000                           %.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e253 8b6c 90&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 ... 3dab 2598&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd5-0xd6 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* Encryption enabled: ephemeral key present (91 bytes)&lt;br /&gt;
* Client sends no certificate, allowing anonymous encryption setup&lt;br /&gt;
* No signature (unsigned OAP)&lt;br /&gt;
* Ephemeral key is ECDHE P-384 for key exchange&lt;br /&gt;
&lt;br /&gt;
==== Packet 8: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the encrypted flow allocation request. FLOW_REPLY contains the server&#039;s ephemeral key but no certificate (since client didn&#039;t send one).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:53.810564 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 180:&lt;br /&gt;
        0x0000:  0000 00a2 0042 0040 0000 0000 0000 0000  .....B.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 00f1 766b 547c  ............vkT|&lt;br /&gt;
        0x0030:  fcb0 8fce 5d60 a01e e8be 0218 86a8 e253  ....]`.........S&lt;br /&gt;
        0x0040:  b694 e800 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0050:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0060:  0004 5f3c 6929 cca2 024a ae9f 9aa1 dfc2  .._&amp;lt;i)...J......&lt;br /&gt;
        0x0070:  a493 3ff3 ff58 b054 74dc d2e2 47fc 7c5b  ..?..X.Tt...G.|[&lt;br /&gt;
        0x0080:  eff5 e129 72b4 de1e 7c09 bf8c fe38 5e8b  ...)r...|....8^.&lt;br /&gt;
        0x0090:  b22e 59ed 6eb9 dfda 369d 691e 6e2c 122c  ..Y.n...6.i.n,.,&lt;br /&gt;
        0x00a0:  9936 0000 0000                           .6....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00a2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 162 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0042 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY with Ephemeral Key&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;f1 766b 547c fcb0 8fce 5d60 a01e e8be 02&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || Echo of client ID || Echoes client&#039;s flow ID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e253 b694 e8&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Echoed timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x46 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x005b (91) || Ephemeral key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x47-0xa1 || &amp;lt;code&amp;gt;30 5930...9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDHE P-384 || Server&#039;s ECDHE P-384 public key (DER encoded)&lt;br /&gt;
|-&lt;br /&gt;
| 0xd1-0xd2 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xd3-0xd4 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID 0x0042 is the new server-side flow endpoint&lt;br /&gt;
* Both keys are now exchanged; client and server can derive shared secret&lt;br /&gt;
* No authentication (no certificates) but encryption is negotiated&lt;br /&gt;
* Response indicates successful allocation&lt;br /&gt;
&lt;br /&gt;
==== Packet 9: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after encryption keys are established. The payload is encrypted with the derived shared secret.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.815771 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0042 0060 a691 6d83 8446 cbeb ac95 c2eb  .B.`..m..F......&lt;br /&gt;
        0x0010:  4b42 e819 c67f 92c8 58d7 0641 d8a6 6e1f  KB......X..A..n.&lt;br /&gt;
        0x0020:  fc90 feed ef55 b791 4fbd a832 74bd 8bed  .....U..O..2t...&lt;br /&gt;
        0x0030:  249c 4cee 0fc0 cec6 2f1b aec1 2428 bdbd  $.L...../...$(..&lt;br /&gt;
        0x0040:  36b5 01b5 1257 004e 6ed6 7ecd f0c7 7d11  6....W.Nn.~...}.&lt;br /&gt;
        0x0050:  20ba e81b f43a 4de9 b141 1624 e1ba 0a84  .....:M..A.$....&lt;br /&gt;
        0x0060:  74b1 9a9a                                t...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0042&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0042 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REQUEST (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;a691 6d83 8446 cbeb...74b1 9a9a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* All 96 bytes of oping data (type, ID, timestamps, payload) are encrypted&lt;br /&gt;
* No plaintext oping headers visible; entire packet is ciphertext&lt;br /&gt;
* Flow IDs (0x0042) identify which encryption context to use&lt;br /&gt;
* Ping still works with encryption transparently&lt;br /&gt;
&lt;br /&gt;
==== Packet 10: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server receives encrypted ping request, decrypts it, and sends encrypted ECHO_REPLY.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:54.819574 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 c6ea 2222 5618 0268 b27e 9a91  .@.`..&amp;quot;&amp;quot;V..h.~..&lt;br /&gt;
        0x0010:  f124 1f8d bccc 478c 26fe 9b13 b3cb 5398  .$....G.&amp;amp;.....S.&lt;br /&gt;
        0x0020:  6869 3cdb 4928 510d 4de8 dc6a 3f3a 6a6d  hi&amp;lt;.I(Q.M..j?:jm&lt;br /&gt;
        0x0030:  6487 dcd8 c8cd 1a85 fba2 9ecd 3566 57d1  d...........5fW.&lt;br /&gt;
        0x0040:  1c94 ac35 518e 8509 873a 3a5e 04d9 8ee2  ...5Q....::^....&lt;br /&gt;
        0x0050:  9d74 2527 e425 5433 9d73 9ccd f56a 1f8d  .t%&#039;.%T3.s...j..&lt;br /&gt;
        0x0060:  f328 7237                                .(r7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0060&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 96 bytes || Encrypted payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Oping Application Protocol - ECHO_REPLY (Encrypted)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x63 || &amp;lt;code&amp;gt;c6ea 2222 5618 0268...f328 7237&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Encrypted Data&#039;&#039;&#039; || 96 || Ciphertext || All 96 bytes encrypted&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID 0x0040 shows reply going back to client-side flow&lt;br /&gt;
* Ciphertext is different from request (different plaintext: type field differs)&lt;br /&gt;
* Both encrypted packets are 96 bytes (same size as Packet 9)&lt;br /&gt;
* Client receives encrypted reply, decrypts it, verifies ID and timestamps match request&lt;br /&gt;
* Encryption is transparent at application layer: oping works exactly as with plaintext flows&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 3 - Authentication and encryption ===&lt;br /&gt;
&lt;br /&gt;
==== Packet 11: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation request with encryption enabled. Sends ephemeral public key for ECDHE key exchange but no certificate (client is not authenticating in this tutorial). The management protocol now carries a valid allocated SEID (0x0040).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.827411 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 212:&lt;br /&gt;
        0x0000:  0000 00c2 0040 0000 0000 0001 0000 0000  .....@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a66 bb82 95fa  ..f.i.._...f....&lt;br /&gt;
        0x0050:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0060:  c0d2 ad00 0000 5b30 5930 1306 072a 8648  ......[0Y0...*.H&lt;br /&gt;
        0x0070:  ce3d 0201 0608 2a86 48ce 3d03 0107 0342  .=....*.H.=....B&lt;br /&gt;
        0x0080:  0004 9dea c238 6732 4987 1cd4 7133 9614  .....8g2I...q3..&lt;br /&gt;
        0x0090:  9d04 4fde 3f68 42f1 54fb 7ef3 88d0 ffe6  ..O.?hB.T.~.....&lt;br /&gt;
        0x00a0:  7e01 432e 56c2 2d64 72c9 19fc b0cf 1eca  ~.C.V.-dr.......&lt;br /&gt;
        0x00b0:  689e 3536 771a 8041 726c 20e2 d9bb 3589  h.56w..Arl....5.&lt;br /&gt;
        0x00c0:  86e7 0000 0000                           ......&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;00c2&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 194 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (client flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... d4c0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || Response code (&#039;&#039;&#039;UNUSED&#039;&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x00 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ... 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload with Encryption Setup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier for Test 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e37e c0d2 ad&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || Client not authenticating&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0xc1 || &amp;lt;code&amp;gt;30 5930 1306 ... 3589&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Client&#039;s ephemeral ECDHE public key for encryption negotiation&lt;br /&gt;
|-&lt;br /&gt;
| 0xc2-0xc3 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0xc4-0xc5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0040 - Same as Test 2 (Encrypted) because this is the same client session reusing the same allocated ID from the previous test&lt;br /&gt;
* No Certificate - &amp;lt;code&amp;gt;crt_len = 0x0000&amp;lt;/code&amp;gt; because the client does not have authentication credentials; the server will authenticate instead&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; because encryption is enabled on the client&lt;br /&gt;
* No Signature - &amp;lt;code&amp;gt;sig_len = 0x0000&amp;lt;/code&amp;gt; because client is not signing (no certificate to sign with)&lt;br /&gt;
* FLOW_REQ Message Type - Code field is 0x00, and service hash is present because FLOW_REQ always includes the service hash&lt;br /&gt;
* Timestamp Consistency - Same OAP ID and timestamp structure as Test 2, but with additional security handshake&lt;br /&gt;
&lt;br /&gt;
==== Packet 12: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds to client&#039;s FLOW_REQ by sending FLOW_REPLY with its certificate for authentication, ephemeral public key for ECDHE encryption setup, and a digital signature proving ownership of the certificate. This is the full authentication response.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:58.828806 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 843:&lt;br /&gt;
        0x0000:  0000 0339 0043 0040 0000 0000 0000 0000  ...9.C.@........&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 0066 bb82 95fa  ...........f....&lt;br /&gt;
        0x0030:  91a2 7bd3 bd60 1b3e 35f6 b918 86a8 e37e  ..{..`.&amp;gt;5......~&lt;br /&gt;
        0x0040:  d566 a002 2f30 8202 2b30 8201 b2a0 0302  .f../0..+0......&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
        0x0320:  ef11 c358 f5d0 5cd7 3906 adf1 8a2c 9b25  ...X..\.9....,.%&lt;br /&gt;
        0x0330:  dc78 6050 ab61 3a3f 81c0 254b d193 7827  .x`P.a:?..%K..x&#039;&lt;br /&gt;
        0x0340:  c0e9 38c7 e0d1 c517 d299 9992 07         ..8..........&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0339&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 825 bytes || Total payload length (excluding DIX header)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0043&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0043 || Source Endpoint ID (server-side allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client&#039;s flow ID from FLOW_REQ)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Default values || QoS parameters&lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Full Authentication&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;66 bb82 95fa 91a2 7bd3 bd60 1b3e 35f6 b9&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;18 86a8 e37e d566 a0&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;022f&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 559 (0x022f) || Server certificate length: 559 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x243 || &amp;lt;code&amp;gt;2f30 8202 2b ... 81c8 30&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 559 || DER-encoded X.509 || Server&#039;s certificate (signed by intermediate CA)&lt;br /&gt;
|-&lt;br /&gt;
| 0x244-0x245 || &amp;lt;code&amp;gt;005b&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 91 (0x005b) || Server&#039;s ephemeral public key length: 91 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x246-0x2a0 || &amp;lt;code&amp;gt;30 5930 1306 ... 9936&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Ephemeral Key&#039;&#039;&#039; || 91 || ECDP-384 public key || Server&#039;s ephemeral ECDHE public key&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a4-0x2a5 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a6-0x2a7 || &amp;lt;code&amp;gt;0068&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 104 (0x0068) || Digital signature length: 104 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a8-0x30f || &amp;lt;code&amp;gt;30 6602 3100 ... 07&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 104 || ECDSA signature (DER encoded) || Server&#039;s signature over OAP header proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0043 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from the FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Full Certificate - &amp;lt;code&amp;gt;crt_len = 0x022f (559)&amp;lt;/code&amp;gt; carrying server&#039;s complete X.509 certificate signed by intermediate CA&lt;br /&gt;
* Ephemeral Key Present - &amp;lt;code&amp;gt;eph_len = 0x005b (91)&amp;lt;/code&amp;gt; with server&#039;s ECDHE public key for encryption&lt;br /&gt;
* Signature Included - &amp;lt;code&amp;gt;sig_len = 0x0068 (104)&amp;lt;/code&amp;gt; containing ECDSA digital signature over the entire OAP header&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ to confirm association (included in signature, binding response to this specific client request)&lt;br /&gt;
* Large Payload - Total of 825 bytes due to certificate (559) + ephemeral key (91) + signature (104) + overhead&lt;br /&gt;
* Authentication Complete - Client verifies: (1) certificate against CA store, (2) signature over entire response ensures authenticity and integrity, (3) echoed ID binds response to this specific request, (4) timestamp prevents replay attacks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with its certificate for authentication, ephemeral public key for ECDHE encryption, and a digital signature proving ownership of the certificate.&lt;br /&gt;
&lt;br /&gt;
==== Packet 13: Encrypted ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends encrypted ping request after authentication handshake. All application data is protected by encryption using the ephemeral keys established in Packets 11-12.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836485 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0043 0060 3bed 0b48 1be1 6930 cf3d dee9  .C.`.;..H..i0.=..&lt;br /&gt;
        0x0010:  4fc9 774b 5d63 cc9b 5a34 6604 f9ac 1016  O.wK]c..Z4f.....&lt;br /&gt;
        0x0020:  1c6d c9ac f80e dc89 31c1 9634 1a4f b2c7  .m......1..4.O..&lt;br /&gt;
        0x0030:  4721 e402 8259 b0aa 8870 4566 33d1 9c18  G!...Y..  .pEf3...&lt;br /&gt;
        0x0040:  06da 50c3 8b75 86b0 f240 d109 840e a6cd  ..P..u...@......&lt;br /&gt;
        0x0050:  d115 77cb 5652 5bfb e6d5 0ca9 dbc3 d0b8  ..w.VR[.........&lt;br /&gt;
        0x0060:  0058 fd19                                .X..&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0043&amp;lt;/code&amp;gt; || Client flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REQUEST data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No visible protocol structure - all application data appears as ciphertext&lt;br /&gt;
* Uses the same source/destination EID pair (0x0043 → 0x0060) established in the FLOW_REQ/FLOW_REPLY handshake&lt;br /&gt;
* Encryption is done using the ephemeral key (91 bytes) exchanged in Packet 11&#039;s OAP header&lt;br /&gt;
* Unlike Packets 11-12, this packet contains no certificate, public keys, or signatures&lt;br /&gt;
* The 110-byte encrypted data corresponds to the original oping ECHO_REQUEST message&lt;br /&gt;
&lt;br /&gt;
==== Packet 14: Encrypted ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server sends encrypted ping reply. Note that the flow identifiers swap, demonstrating bidirectional encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:39:59.836930 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 114:&lt;br /&gt;
        0x0000:  0040 0060 d552 e100 e681 940c e35a 07d0  .@.`..........Z..&lt;br /&gt;
        0x0010:  a293 1d73 33a5 854e 0fce 4f4d 6655 267a  ...s3..N..OMfU&amp;amp;z&lt;br /&gt;
        0x0020:  3de2 663b 709d 739a a696 2ddd 7b34 28b8  =.f;p.s...-{4(...&lt;br /&gt;
        0x0030:  5a98 eec2 52c6 4288 3885 ae16 e466 4181  Z...R.B.8...fA..&lt;br /&gt;
        0x0040:  f2d6 44c1 b51b 8728 58a4 7525 fb5e 3fd6  ..D...(X.u%.^?..&lt;br /&gt;
        0x0050:  7e49 532a d2a5 bea7 55e9 c274 f1b2 0412  ~IS*....U..t....&lt;br /&gt;
        0x0060:  73d4 6436                                s.d6&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame Analysis:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Offset !! Length !! Value !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Source EID || 0x00-0x01 || 2 bytes || &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt; || Client&#039;s inbound flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| Destination EID || 0x02-0x03 || 2 bytes || &amp;lt;code&amp;gt;0x0060&amp;lt;/code&amp;gt; || Server flow endpoint ID&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Encrypted Payload&#039;&#039;&#039; || &#039;&#039;&#039;0x04-0x71&#039;&#039;&#039; || &#039;&#039;&#039;110 bytes&#039;&#039;&#039; || &#039;&#039;&#039;Ciphertext&#039;&#039;&#039; || &#039;&#039;&#039;AES-encrypted oping ECHO_REPLY data&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* The EID in offset 0x00 is now 0x0040 (server&#039;s view of client&#039;s inbound flow)&lt;br /&gt;
* Uses the same ephemeral key material as Packet 13, but encryption direction is reversed&lt;br /&gt;
* Both packets use AES-GCM with keys derived from the ECDH exchange&lt;br /&gt;
* Timestamp 17:39:59.836930 is only 445 microseconds after Packet 13, indicating server-side processing&lt;br /&gt;
* The 110-byte encrypted ECHO_REPLY payload is the same size as the request&lt;br /&gt;
* All application data is protected by both authentication (X.509 + ECDSA) and encryption (AES)&lt;br /&gt;
&lt;br /&gt;
=== Packet Analysis: Test 4 - Authentication, no encryption ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Packet 15: FLOW_REQ ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client initiates flow allocation with authentication enabled but encryption disabled. This FLOW_REQ carries an OAP header but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since the client does not request encrypted communication.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.413372 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 121:&lt;br /&gt;
        0x0000:  0000 0067 0040 0000 0000 0001 0000 0000  ...g.@..........&lt;br /&gt;
        0x0010:  0000 0000 0000 0001 ffff ffff ffff ffff  ................&lt;br /&gt;
        0x0020:  0001 d4c0 0000 0000 0000 00ec f815 ad98  ................&lt;br /&gt;
        0x0030:  3df6 bf81 fdc7 cb63 6eec 1563 6e60 5a94  =......cn..cn`Z.&lt;br /&gt;
        0x0040:  b1ad 66c1 690c 9e5f 9282 8a8f a6ab 6ea7  ..f.i.._........&lt;br /&gt;
        0x0050:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0060:  0de6 6100 0000 0000 0000 00              ..a.....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 103 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0040 || Source Endpoint ID (allocated flow ID)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... dc40&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || Mixed || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0 || &#039;&#039;&#039;UNUSED&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REQ&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x4a || &amp;lt;code&amp;gt;ec f815 ad98 3df6 bf81...9282 8a&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Service Hash&#039;&#039;&#039; || 32 || SHA3-256 || Hash of &amp;lt;code&amp;gt;sec.oping.tut.o7s&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REQ Payload (No Encryption)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x4b-0x5a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919 fa&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || Unique flow allocation identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x5b-0x62 || &amp;lt;code&amp;gt;18 86a8 e490 0de6 61&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Creation timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x63-0x64 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x0000 || No certificate in client request&lt;br /&gt;
|-&lt;br /&gt;
| 0x65-0x66 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key (no encryption)&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x67-0x68 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x69-0x6a || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0000 || No signature&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* No encryption enabled: ephemeral key absent (Eph_len = 0x0000)&lt;br /&gt;
* Client requests authentication only&lt;br /&gt;
* Server will respond with certificate + signature but no ephemeral key&lt;br /&gt;
* Packet is minimal compared to Packet 11 (Test 3) which includes 91-byte ephemeral key&lt;br /&gt;
&lt;br /&gt;
==== Packet 16: FLOW_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server accepts the authenticated (but not encrypted) flow allocation request. FLOW_REPLY contains the server&#039;s X.509 certificate and ECDSA signature for client authentication, but &#039;&#039;&#039;no ephemeral key&#039;&#039;&#039; since encryption is not being used.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data (abbreviated):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:03.416675 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 751:&lt;br /&gt;
        0x0000:  0000 02dd 0041 0040 0000 0000 0000 0000  .......A.@......&lt;br /&gt;
        0x0010:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0001 008f a6ab 6ea7  ................&lt;br /&gt;
        0x0030:  ef89 68e1 ed1e 2ede 0919 fa18 86a8 e490  .h..............&lt;br /&gt;
        0x0040:  3754 a702 2f30 8202 2b30 8201 b2a0 0302  7T../0..+0......&lt;br /&gt;
        0x0050:  0102 0202 1000 300a 0608 2a86 48ce 3d04  ......0...*.H.=.&lt;br /&gt;
        (... certificate and signature bytes ...)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0000 || Destination Endpoint ID (management channel)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;02dd&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 733 bytes || Total payload length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet Flow Allocator - Management Protocol&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x05 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;SEID&#039;&#039;&#039; || 2 || 0x0041 || Source Endpoint ID (allocated server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x06-0x07 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;DEID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x23 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Various)&#039;&#039;&#039; || 28 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x24-0x27 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Response&#039;&#039;&#039; || 4 || 0x00000000 || Response code: 0 (success)&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (In-Order)&#039;&#039;&#039; || 1 || 0 || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || &amp;lt;code&amp;gt;01&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Code&#039;&#039;&#039; || 1 || 0x01 || Message Type: FLOW_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x2a || &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt; || &#039;&#039;&#039;QoS (Availability)&#039;&#039;&#039; || 1 || 0x00 || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ouroboros Allocation Protocol (OAP) - FLOW_REPLY Payload with Certificate and Signature (No Ephemeral Key)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x2b-0x3a || &amp;lt;code&amp;gt;8f a6ab 6ea7 ef89 68e1 ed1e 2ede 0919&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 16 || 128-bit identifier || &#039;&#039;&#039;Same ID as client&#039;s FLOW_REQ&#039;&#039;&#039; (Packet 15 echoed back)&lt;br /&gt;
|-&lt;br /&gt;
| 0x3b-0x42 || &amp;lt;code&amp;gt;fa18 86a8 e490 3754&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp&#039;&#039;&#039; || 8 || Network order || Server&#039;s timestamp&lt;br /&gt;
|-&lt;br /&gt;
| 0x43-0x44 || &amp;lt;code&amp;gt;a702&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Crt_len&#039;&#039;&#039; || 2 || 0x02a7 (679 decimal) || &#039;&#039;&#039;Certificate length: 679 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x45-0x270 || &amp;lt;code&amp;gt;2f30 8202 2b30 8201 b2a0 0302 ... (DER certificate) ...&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Certificate&#039;&#039;&#039; || 679 || DER-encoded X.509 || Server&#039;s certificate signed by intermediate CA&lt;br /&gt;
|-&lt;br /&gt;
| 0x271-0x272 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Eph_len&#039;&#039;&#039; || 2 || 0x0000 || &#039;&#039;&#039;No ephemeral key&#039;&#039;&#039; (no encryption)&lt;br /&gt;
|-&lt;br /&gt;
| 0x273-0x274 || &amp;lt;code&amp;gt;0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Data_len&#039;&#039;&#039; || 2 || 0x0000 || No application data&lt;br /&gt;
|-&lt;br /&gt;
| 0x275-0x276 || &amp;lt;code&amp;gt;0067&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Sig_len&#039;&#039;&#039; || 2 || 0x0067 (103 decimal) || &#039;&#039;&#039;ECDSA signature length: 103 bytes&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| 0x277-0x2dd || &amp;lt;code&amp;gt;3065 0230 75dc 5717 ... 83&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Signature&#039;&#039;&#039; || 103 || ECDSA signature (DER encoded) || Server&#039;s ECDSA signature proving certificate ownership&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* SEID is 0x0041 - New server-side endpoint ID allocated for this authenticated flow&lt;br /&gt;
* DEID is 0x0040 - Client&#039;s flow ID from Packet 15 FLOW_REQ, establishing the bidirectional flow&lt;br /&gt;
* FLOW_REPLY Message Type - Code field is 0x01, &#039;&#039;&#039;no service hash&#039;&#039;&#039; (already identified in FLOW_REQ)&lt;br /&gt;
* Certificate Field - &amp;lt;code&amp;gt;crt_len = 0x02a7 (679)&amp;lt;/code&amp;gt; carrying server&#039;s X.509 certificate signed by intermediate CA&lt;br /&gt;
* Separate Signature Field - &amp;lt;code&amp;gt;sig_len = 0x0067 (103)&amp;lt;/code&amp;gt; with ECDSA signature over entire OAP header&lt;br /&gt;
* No Ephemeral Key - &amp;lt;code&amp;gt;eph_len = 0x0000&amp;lt;/code&amp;gt; since encryption is &#039;&#039;&#039;not&#039;&#039;&#039; being used in Test 4&lt;br /&gt;
* Same OAP ID - Server echoes back the exact ID from client&#039;s FLOW_REQ (included in signature, binding response to this specific client request)&lt;br /&gt;
* Complete OAP Structure - Full OAP header with all standard fields, just without ephemeral key data&lt;br /&gt;
* Plaintext Data Exchange - After this FLOW_REPLY, all subsequent application data will be transmitted in plaintext (but authenticated via certificate + signature verification)&lt;br /&gt;
&lt;br /&gt;
==== Packet 17: ECHO_REQUEST ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Client sends plaintext ECHO_REQUEST data through the authenticated (but unencrypted) flow. The oping application&#039;s ping request is transmitted directly without encryption, relying on the earlier certificate+signature authentication for security.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.419664 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0041 0040 0000 0000 0000 0000 8177 0000  .A.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0041&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0041 || Destination Endpoint ID (server flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Request (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000000 || Message type: ECHO_REQUEST&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Sequence number / message identifier&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Seconds component from CLOCK_REALTIME&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Nanoseconds component (0-999999999)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0041 → Server Flow - Data is directed to the server&#039;s endpoint ID allocated in Packet 16 FLOW_REPLY&lt;br /&gt;
* Plaintext Transmission - No encryption layer; oping payload is sent as-is (compare to Packet 13 which had encryption)&lt;br /&gt;
* Authenticated Flow - Although plaintext, this data travels on the authenticated flow established in Packet 16 (certificate + signature verified)&lt;br /&gt;
* Type = ECHO_REQUEST - 0x00000000 indicates client-to-server ping request&lt;br /&gt;
* ID = 0 - Sequence number for matching request/reply pairs&lt;br /&gt;
* Test 4 Characteristic - Demonstrates authenticated communication &#039;&#039;&#039;without&#039;&#039;&#039; encryption; application data is readable but cryptographically bound to the authenticated flow&lt;br /&gt;
* Contrast to Test 3 - Packet 13 (Test 3 encrypted ECHO_REQUEST) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;br /&gt;
&lt;br /&gt;
==== Packet 18: ECHO_REPLY ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Summary:&#039;&#039;&#039; Server responds with plaintext ECHO_REPLY data, echoing back the client&#039;s request. This confirms successful bidirectional communication over the authenticated (but unencrypted) flow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Raw Data:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
17:40:04.420088 00:00:00:00:00:00 &amp;gt; 00:00:00:00:00:00, ethertype Unknown (0xa000), length 82:&lt;br /&gt;
        0x0000:  0040 0040 0000 0001 0000 0000 8177 0000  .@.@............&lt;br /&gt;
        0x0010:  0000 0000 aa16 1c16 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;
        0x0040:  0000 0000                                ....&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ethernet DIX Frame with EID Header&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x00-0x01 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;EID&#039;&#039;&#039; || 2 || 0x0040 || Destination Endpoint ID (client flow)&lt;br /&gt;
|-&lt;br /&gt;
| 0x02-0x03 || &amp;lt;code&amp;gt;0040&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Length&#039;&#039;&#039; || 2 || 64 bytes || Total application data length&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Application Data - Oping Echo Reply (Plaintext)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset !! Hex !! Field !! Size !! Value !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| 0x04-0x07 || &amp;lt;code&amp;gt;0000 0001&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Type&#039;&#039;&#039; || 4 || 0x00000001 || Message type: ECHO_REPLY&lt;br /&gt;
|-&lt;br /&gt;
| 0x08-0x0b || &amp;lt;code&amp;gt;0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;ID&#039;&#039;&#039; || 4 || 0x00000000 || Echo of request sequence number&lt;br /&gt;
|-&lt;br /&gt;
| 0x0c-0x13 || &amp;lt;code&amp;gt;8177 0000 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (seconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x14-0x1b || &amp;lt;code&amp;gt;aa16 1c16 0000 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Timestamp (nanoseconds)&#039;&#039;&#039; || 8 || Network-byte-order 64-bit || Echoed request timestamp (nanoseconds)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1c-0x43 || &amp;lt;code&amp;gt;0000 ... 0000&amp;lt;/code&amp;gt; || &#039;&#039;&#039;Payload&#039;&#039;&#039; || 40 || Application data || Echoed probe payload (zero-filled for 64 bytes total)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Key observations:&#039;&#039;&#039;&lt;br /&gt;
* EID Pair: 0x0040 → Client Flow - Server responds to client&#039;s endpoint ID from Packet 15 FLOW_REQ&lt;br /&gt;
* Type = ECHO_REPLY - 0x00000001 indicates server-to-client response&lt;br /&gt;
* ID = 0 - Echoes the request sequence number, matching this response to the request&lt;br /&gt;
* Timestamps Echo Request - Both timestamp fields are copied from Packet 17 unchanged (8177 0000 0000 0000 and aa16 1c16 0000 0000)&lt;br /&gt;
* Plaintext Reply - No encryption; server&#039;s response payload is readable (compare to Packet 14 which had encryption)&lt;br /&gt;
* Authenticated Channel - Although plaintext, this reply is part of the authenticated flow; client can verify integrity through earlier certificate+signature&lt;br /&gt;
* Test 4 Completion - Demonstrates &#039;&#039;&#039;full bidirectional plaintext communication&#039;&#039;&#039; over an authenticated (but unencrypted) flow&lt;br /&gt;
* Contrast to Test 3 - Packet 14 (Test 3 encrypted ECHO_REPLY) was 114 bytes with ciphertext; this packet is 82 bytes of plaintext&lt;br /&gt;
* Total Payload - 64 bytes total (4 + 4 + 8 + 8 + 40 bytes payload)&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Rumba&amp;diff=1886</id>
		<title>Rumba</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Rumba&amp;diff=1886"/>
		<updated>2026-01-18T10:07:51Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Install Rumba */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}} (see https://ouroboros.rocks/docs/tools/rumba/)&lt;br /&gt;
&lt;br /&gt;
Rumba is a Python framework for setting up Ouroboros and RINA networks in a test environment that was developed during the [[History of Ouroboros#2016:_ARCFIRE_and_the_start_of_Ouroboros | ARCFIRE]] project. Its main objectives are to configure networks and to evaluate the impact of the architecture on configuration management and devops in computer and telecommunications networks. The original Rumba project page is [https://gitlab.com/ARCFIRE/Rumba here].&lt;br /&gt;
&lt;br /&gt;
Rumba can quickly set up test networks for Ouroboros that are made up of many IPCPs and Layers. We keep a version on this site up-to-date with the Ouroboros prototype.&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
&lt;br /&gt;
* easily define network topologies&lt;br /&gt;
&lt;br /&gt;
* Support for different prototypes:&lt;br /&gt;
** Ouroboros&amp;lt;ref&amp;gt;Only Ouroboros is maintained in our git clone, it may not work anymore with rlite and IRATI.&amp;lt;/ref&amp;gt;&lt;br /&gt;
** rlite&lt;br /&gt;
** IRATI&lt;br /&gt;
&lt;br /&gt;
* create these networks using different possible environments:&lt;br /&gt;
** local PC (Ouroboros only)&lt;br /&gt;
** docker container&lt;br /&gt;
** virtual machine (qemu)&lt;br /&gt;
** [https://jfed.ilabt.imec.be/ jFed] testbeds&lt;br /&gt;
&lt;br /&gt;
* script experiments&lt;br /&gt;
&lt;br /&gt;
* rudimentary support for drawing these networks (using pydot)&lt;br /&gt;
&lt;br /&gt;
== Install Rumba ==&lt;br /&gt;
We forked Rumba with the Ouroboros website, and you should get this forked version for use with Ouroboros.&lt;br /&gt;
It should work with most python versions, but I recommend using a recent version (currently &amp;gt;= Python3.9).&lt;br /&gt;
&lt;br /&gt;
 git clone https://ouroboros.rocks/git/rumba&lt;br /&gt;
 cd rumba&lt;br /&gt;
 # Recommended: create/enter python virtual environment (e.g. the same created for [[Ouroboros Metrics|InfluxDB &amp;amp; grafana]]), or to create one:&lt;br /&gt;
 python -m venv ./venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 pip install --upgrade pip &lt;br /&gt;
 # If not, then it will install system-wide (use sudo in that case)&lt;br /&gt;
 pip install .&lt;br /&gt;
 # OR, if you want all 3 extra features&lt;br /&gt;
 pip install &amp;quot;.[NumpyAcceleration,graphs,visualizer]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Use Rumba ==&lt;br /&gt;
The Rumba model is heavily based on [[RINA]] terminology (since it was originally developed within a RINA research project). We will probably align the terminology in Rumba with Ouroboros in the near future. I will break down a typical Rumba experiment definition and show how to use Rumba in Python interactive mode. You can download the complete example experiment definition [https://{{SERVERNAME}}/docs/tools/rumba_example.py here]. The example uses the Ouroboros prototype, and we will run the setup on the local testbed since that is available on any machine and doesn’t require additional dependencies. We use the local testbed a lot for quick development testing and debugging. I will also show the experiment definition for the virtual wall server testbed at Ghent University as an example for researchers who have access to this testbed. If you have docker or qemu installed, feel free to experiment with these at your leisure.&lt;br /&gt;
&lt;br /&gt;
If you want to test Ouroboros locally (no docker/qemu), then the only example script you can run without modification is:&lt;br /&gt;
 python3 examples/scalingtime.py --prototype ouroboros local&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1884</id>
		<title>Ouroboros Protocols</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1884"/>
		<updated>2026-01-08T20:54:14Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Flow Allocation Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
&lt;br /&gt;
The protocols in Ouroboros are designed with strong adherence to the principles of [https://en.wikipedia.org/wiki/Separation_of_concerns separation of concerns] and [https://en.wikipedia.org/wiki/Separation_of_mechanism_and_policy separation of mechanism and policy] in mind to prevent network ossification and protocol ossification from occuring.&lt;br /&gt;
&lt;br /&gt;
There are 5 core protocols in Ouroboros.&lt;br /&gt;
&lt;br /&gt;
== Data Transfer Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Data Transfer Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Data Transfer Protocol resides in the [[Ouroboros Functional Layering|network forwarding layer]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                      Destination Address                      +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |  Time-to-Live |      QoS      |      ECN      |    PADDING    |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                              EID                              +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                           N + 1 Data                          +&lt;br /&gt;
 .                                                               .&lt;br /&gt;
 .                                                               .&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow and Retransmission Control Protocol ==&lt;br /&gt;
Main page: [[Flow and Retransmission Control Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Flow and Retransmission Control Protocol resides in the [[Ouroboros Functional Layering|application end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |            Flags              |            Window             |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                        Sequence Number                        |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                    Acknowledgment Number                      |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow Allocation Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Flow Allocation Protocol]]&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 *  0                   1                   2                   3&lt;br /&gt;
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                      id (128 bits)                            +    |&lt;br /&gt;
 * |                  Unique flow allocation ID                    |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                     timestamp (64 bits)                       +    |&lt;br /&gt;
 * |                UTC nanoseconds since epoch                    |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |         crt_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                  certificate (variable)                       +    |&lt;br /&gt;
 * |               X.509 certificate, DER encoded                  |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |F|R|     kex_len (14 bits)     |                               |    | Signed&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    | Region&lt;br /&gt;
 * +                 kex_data (variable)                           +    |&lt;br /&gt;
 * |      public key (DER/raw) or ciphertext (KEM)                 |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |       cipher_len (16 bits)    |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    cipher (variable)                          +    |&lt;br /&gt;
 * |               symmetric cipher name (UTF-8)                   |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |        data_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    data (variable)                            +    |&lt;br /&gt;
 * |              Piggybacked application data                     |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |        sig_len (16 bits)      |                               |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +&lt;br /&gt;
 * |                                                               |&lt;br /&gt;
 * +                     signature (variable)                      +&lt;br /&gt;
 * |                  DSA signature over signed region             |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 *&lt;br /&gt;
 * kex_len field bit layout:&lt;br /&gt;
 *   F (bit 15): Format - 0 = X.509 DER, 1 = Raw/Hybrid&lt;br /&gt;
 *   R (bit 14): Role   - 0 = Server encaps, 1 = Client encaps&lt;br /&gt;
 *               (R is ignored for non-KEM algorithms)&lt;br /&gt;
 *   Bits 0-13:  Length (0-16383 bytes)&lt;br /&gt;
 */&lt;br /&gt;
The Flow Allocation Protocol resides in the [[Ouroboros Functional Layering|network end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
== Connection Establishment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Connection Establishment Protocol]]&lt;br /&gt;
&lt;br /&gt;
== Enrollment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Enrolment Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Enrollment protocol is best seen as one of the application protocols for IPCPs.&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1883</id>
		<title>Ouroboros Protocols</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1883"/>
		<updated>2026-01-08T20:38:21Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Flow Allocation Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
&lt;br /&gt;
The protocols in Ouroboros are designed with strong adherence to the principles of [https://en.wikipedia.org/wiki/Separation_of_concerns separation of concerns] and [https://en.wikipedia.org/wiki/Separation_of_mechanism_and_policy separation of mechanism and policy] in mind to prevent network ossification and protocol ossification from occuring.&lt;br /&gt;
&lt;br /&gt;
There are 5 core protocols in Ouroboros.&lt;br /&gt;
&lt;br /&gt;
== Data Transfer Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Data Transfer Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Data Transfer Protocol resides in the [[Ouroboros Functional Layering|network forwarding layer]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                      Destination Address                      +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |  Time-to-Live |      QoS      |      ECN      |    PADDING    |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                              EID                              +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                           N + 1 Data                          +&lt;br /&gt;
 .                                                               .&lt;br /&gt;
 .                                                               .&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow and Retransmission Control Protocol ==&lt;br /&gt;
Main page: [[Flow and Retransmission Control Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Flow and Retransmission Control Protocol resides in the [[Ouroboros Functional Layering|application end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |            Flags              |            Window             |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                        Sequence Number                        |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                    Acknowledgment Number                      |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow Allocation Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Flow Allocation Protocol]]&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 *  0                   1                   2                   3&lt;br /&gt;
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                      id (128 bits)                            +    |&lt;br /&gt;
 * |                  Unique flow allocation ID                    |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                     timestamp (64 bits)                       +    |&lt;br /&gt;
 * |                UTC nanoseconds since epoch                    |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |         crt_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                  certificate (variable)                       +    |&lt;br /&gt;
 * |               X.509 certificate, DER encoded                  |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |         kex_len (16 bits)     |                               |    | Signed&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    | Region&lt;br /&gt;
 * +                 kex_data (variable)                           +    |&lt;br /&gt;
 * |                  public key, DER encoded                      |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |       cipher_len (16 bits)    |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    cipher (variable)                          +    |&lt;br /&gt;
 * |               symmetric cipher name (UTF-8)                   |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |        data_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    data (variable)                            +    |&lt;br /&gt;
 * |              Piggybacked application data                     |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |        sig_len (16 bits)      |                               |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +&lt;br /&gt;
 * |                                                               |&lt;br /&gt;
 * +                     signature (variable)                      +&lt;br /&gt;
 * |                  DSA signature over signed region             |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&lt;br /&gt;
The Flow Allocation Protocol resides in the [[Ouroboros Functional Layering|network end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
== Connection Establishment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Connection Establishment Protocol]]&lt;br /&gt;
&lt;br /&gt;
== Enrollment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Enrolment Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Enrollment protocol is best seen as one of the application protocols for IPCPs.&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1882</id>
		<title>Ouroboros Protocols</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1882"/>
		<updated>2026-01-08T20:37:57Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Flow Allocation Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
&lt;br /&gt;
The protocols in Ouroboros are designed with strong adherence to the principles of [https://en.wikipedia.org/wiki/Separation_of_concerns separation of concerns] and [https://en.wikipedia.org/wiki/Separation_of_mechanism_and_policy separation of mechanism and policy] in mind to prevent network ossification and protocol ossification from occuring.&lt;br /&gt;
&lt;br /&gt;
There are 5 core protocols in Ouroboros.&lt;br /&gt;
&lt;br /&gt;
== Data Transfer Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Data Transfer Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Data Transfer Protocol resides in the [[Ouroboros Functional Layering|network forwarding layer]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                      Destination Address                      +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |  Time-to-Live |      QoS      |      ECN      |    PADDING    |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                              EID                              +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                           N + 1 Data                          +&lt;br /&gt;
 .                                                               .&lt;br /&gt;
 .                                                               .&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow and Retransmission Control Protocol ==&lt;br /&gt;
Main page: [[Flow and Retransmission Control Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Flow and Retransmission Control Protocol resides in the [[Ouroboros Functional Layering|application end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |            Flags              |            Window             |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                        Sequence Number                        |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                    Acknowledgment Number                      |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow Allocation Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Flow Allocation Protocol]]&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 *  0                   1                   2                   3&lt;br /&gt;
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                      id (128 bits)                            +    |&lt;br /&gt;
 * |                  Unique flow allocation ID                    |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                     timestamp (64 bits)                       +    |&lt;br /&gt;
 * |                UTC nanoseconds since epoch                    |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |         crt_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                  certificate (variable)                       +    |&lt;br /&gt;
 * |               X.509 certificate, DER encoded                  |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |         kex_len (16 bits)     |                               |    | Signed&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |&lt;br /&gt;
 * +                 kex_data (variable)                           +    |&lt;br /&gt;
 * |                  public key, DER encoded                      |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |       cipher_len (16 bits)    |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    cipher (variable)                          +    |&lt;br /&gt;
 * |               symmetric cipher name (UTF-8)                   |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |        data_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    data (variable)                            +    |&lt;br /&gt;
 * |              Piggybacked application data                     |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |        sig_len (16 bits)      |                               |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +&lt;br /&gt;
 * |                                                               |&lt;br /&gt;
 * +                     signature (variable)                      +&lt;br /&gt;
 * |                  DSA signature over signed region             |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&lt;br /&gt;
The Flow Allocation Protocol resides in the [[Ouroboros Functional Layering|network end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
== Connection Establishment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Connection Establishment Protocol]]&lt;br /&gt;
&lt;br /&gt;
== Enrollment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Enrolment Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Enrollment protocol is best seen as one of the application protocols for IPCPs.&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1881</id>
		<title>Ouroboros Protocols</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1881"/>
		<updated>2026-01-08T20:36:16Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Flow Allocation Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
&lt;br /&gt;
The protocols in Ouroboros are designed with strong adherence to the principles of [https://en.wikipedia.org/wiki/Separation_of_concerns separation of concerns] and [https://en.wikipedia.org/wiki/Separation_of_mechanism_and_policy separation of mechanism and policy] in mind to prevent network ossification and protocol ossification from occuring.&lt;br /&gt;
&lt;br /&gt;
There are 5 core protocols in Ouroboros.&lt;br /&gt;
&lt;br /&gt;
== Data Transfer Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Data Transfer Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Data Transfer Protocol resides in the [[Ouroboros Functional Layering|network forwarding layer]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                      Destination Address                      +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |  Time-to-Live |      QoS      |      ECN      |    PADDING    |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                              EID                              +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                           N + 1 Data                          +&lt;br /&gt;
 .                                                               .&lt;br /&gt;
 .                                                               .&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow and Retransmission Control Protocol ==&lt;br /&gt;
Main page: [[Flow and Retransmission Control Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Flow and Retransmission Control Protocol resides in the [[Ouroboros Functional Layering|application end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |            Flags              |            Window             |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                        Sequence Number                        |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                    Acknowledgment Number                      |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow Allocation Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Flow Allocation Protocol]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 0                   1                   2                   3&lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                                                               +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                       id (128 bits)                           +    |&lt;br /&gt;
|                  Unique flow allocation ID                    |    |&lt;br /&gt;
+                                                               +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                     timestamp (64 bits)                       +    |&lt;br /&gt;
|                 UTC nanoseconds since epoch                   |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|         crt_len (16 bits)     |                               |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                                                               +    |&lt;br /&gt;
|                  certificate (variable)                       |    |&lt;br /&gt;
+               X.509 certificate, DER encoded                  +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                               |         eph_len (16 bits)     |    |  Signed&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |  Region&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                                                               +    |&lt;br /&gt;
|                 ephemeral_key (variable)                      |    |&lt;br /&gt;
+              public key, DER encoded                          +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                               |        data_len (16 bits)     |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                     data (variable)                           +    |&lt;br /&gt;
|              Piggybacked application data                     |    |&lt;br /&gt;
+                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                               |         sig_len (16 bits)     |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
|                                                               |&lt;br /&gt;
+                                                               +&lt;br /&gt;
|                   signature (variable)                        |&lt;br /&gt;
+                  DSA signature over signed region             +&lt;br /&gt;
|                                                               |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Flow Allocation Protocol resides in the [[Ouroboros Functional Layering|network end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
== Connection Establishment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Connection Establishment Protocol]]&lt;br /&gt;
&lt;br /&gt;
== Enrollment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Enrolment Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Enrollment protocol is best seen as one of the application protocols for IPCPs.&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1880</id>
		<title>Ouroboros Protocols</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Protocols&amp;diff=1880"/>
		<updated>2026-01-08T20:35:46Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Data Transfer Protocol */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
&lt;br /&gt;
The protocols in Ouroboros are designed with strong adherence to the principles of [https://en.wikipedia.org/wiki/Separation_of_concerns separation of concerns] and [https://en.wikipedia.org/wiki/Separation_of_mechanism_and_policy separation of mechanism and policy] in mind to prevent network ossification and protocol ossification from occuring.&lt;br /&gt;
&lt;br /&gt;
There are 5 core protocols in Ouroboros.&lt;br /&gt;
&lt;br /&gt;
== Data Transfer Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Data Transfer Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Data Transfer Protocol resides in the [[Ouroboros Functional Layering|network forwarding layer]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                      Destination Address                      +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |  Time-to-Live |      QoS      |      ECN      |    PADDING    |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                              EID                              +&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                                                               |&lt;br /&gt;
 +                           N + 1 Data                          +&lt;br /&gt;
 .                                                               .&lt;br /&gt;
 .                                                               .&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow and Retransmission Control Protocol ==&lt;br /&gt;
Main page: [[Flow and Retransmission Control Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Flow and Retransmission Control Protocol resides in the [[Ouroboros Functional Layering|application end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
  0                   1                   2                   3&lt;br /&gt;
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |            Flags              |            Window             |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                        Sequence Number                        |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 |                    Acknowledgment Number                      |&lt;br /&gt;
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Flow Allocation Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Flow Allocation Protocol]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 0                   1                   2                   3&lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                                                               +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                       id (128 bits)                           +    |&lt;br /&gt;
|                  Unique flow allocation ID                    |    |&lt;br /&gt;
+                                                               +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                     timestamp (64 bits)                       +    |&lt;br /&gt;
|                 UTC nanoseconds since epoch                   |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|         crt_len (16 bits)     |                               |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                                                               +    |&lt;br /&gt;
|                  certificate (variable)                       |    |&lt;br /&gt;
+               X.509 certificate, DER encoded                  +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                               |         eph_len (16 bits)     |    |  Signed&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |  Region&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                                                               +    |&lt;br /&gt;
|                 ephemeral_key (variable)                      |    |&lt;br /&gt;
+              public key, DER encoded                          +    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                               |        data_len (16 bits)     |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                                                               |    |&lt;br /&gt;
+                     data (variable)                           +    |&lt;br /&gt;
|              Piggybacked application data                     |    |&lt;br /&gt;
+                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
|                               |         sig_len (16 bits)     |    |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
|                                                               |&lt;br /&gt;
+                                                               +&lt;br /&gt;
|                   signature (variable)                        |&lt;br /&gt;
+                  DSA signature over signed region             +&lt;br /&gt;
|                                                               |&lt;br /&gt;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Flow Allocation Protocol resides in the [[Ouroboros Functional Layering|network end-to-end layer]].&lt;br /&gt;
&lt;br /&gt;
A comparison with TLS 1.3 (generated by Claude Opus 4.5 based on the O7s codebase): [[Flow Allocation vs TLS]]&lt;br /&gt;
&lt;br /&gt;
== Connection Establishment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Connection Establishment Protocol]]&lt;br /&gt;
&lt;br /&gt;
== Enrollment Protocol ==&lt;br /&gt;
Main page: [[Ouroboros Enrolment Protocol]]&lt;br /&gt;
&lt;br /&gt;
The Enrollment protocol is best seen as one of the application protocols for IPCPs.&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Flow_Allocation_Protocol&amp;diff=1879</id>
		<title>Ouroboros Flow Allocation Protocol</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Ouroboros_Flow_Allocation_Protocol&amp;diff=1879"/>
		<updated>2026-01-07T00:02:49Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Header */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
&lt;br /&gt;
= Header =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
OAP Header Structure&lt;br /&gt;
====================&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 *  0                   1                   2                   3&lt;br /&gt;
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                      id (128 bits)                            +    |&lt;br /&gt;
 * |                  Unique flow allocation ID                    |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                     timestamp (64 bits)                       +    |&lt;br /&gt;
 * |                UTC nanoseconds since epoch                    |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |         crt_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                  certificate (variable)                       +    |&lt;br /&gt;
 * |               X.509 certificate, DER encoded                  |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |         eph_len (16 bits)     |                               |    | Signed&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    | Region&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                 ephemeral_key (variable)                      +    |&lt;br /&gt;
 * |                  public key, DER encoded                      |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |       cipher_len (16 bits)    |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    cipher (variable)                          +    |&lt;br /&gt;
 * |               symmetric cipher name (UTF-8)                   |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |&lt;br /&gt;
 * |        data_len (16 bits)     |                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +                    data (variable)                            +    |&lt;br /&gt;
 * |              Piggybacked application data                     |    |&lt;br /&gt;
 * +                                                               +    |&lt;br /&gt;
 * |                                                               |    |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ---+&lt;br /&gt;
 * |        sig_len (16 bits)      |                               |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +&lt;br /&gt;
 * |                                                               |&lt;br /&gt;
 * +                     signature (variable)                      +&lt;br /&gt;
 * |                  DSA signature over signed region             |&lt;br /&gt;
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
Field Summary:&lt;br /&gt;
+---------------+----------+----------------------------------------+&lt;br /&gt;
| Field         | Size     | Description                            |&lt;br /&gt;
+---------------+----------+----------------------------------------+&lt;br /&gt;
| id            | 16 bytes | Random 128-bit flow allocation ID      |&lt;br /&gt;
| timestamp     |  8 bytes | UTC time in nanoseconds (replay prot.) |&lt;br /&gt;
| crt_len       |  2 bytes | Certificate length (0 = no auth)       |&lt;br /&gt;
| certificate   | variable | X.509 cert signed by CA (DER encoded)  |&lt;br /&gt;
| eph_len       |  2 bytes | Ephemeral key length (0 = no encrypt)  |&lt;br /&gt;
| ephemeral_key | variable | DHE public key                         |&lt;br /&gt;
| cipher_len    |  2 bytes | Cipher name length (0 = no cipher)     |&lt;br /&gt;
| cipher        | variable | Name of the cipher to use              |&lt;br /&gt;
| data_len      |  2 bytes | Application data length                |&lt;br /&gt;
| data          | variable | Piggybacked app data (future use)      |&lt;br /&gt;
| sig_len       |  2 bytes | Signature length (0 = unsigned)        |&lt;br /&gt;
| signature     | variable | Signature                              |&lt;br /&gt;
+---------------+----------+----------------------------------------+&lt;br /&gt;
&lt;br /&gt;
Minimum header size: 16 + 8 + 2 + 2 + 2 + 2 + 2 = 34 bytes (no optional fields)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Operation =&lt;br /&gt;
&lt;br /&gt;
When an application calls flow_alloc() to connect to a service or flow_accept() to receive incoming connections, the Ouroboros IRMd (IPC Resource Manager daemon) transparently handles all security operations on behalf of the application. The application simply provides a destination name (e.g., &amp;quot;sec.oping.tut.o7s&amp;quot;) and receives back a flow descriptor for reading and writing data—it remains completely unaware of any underlying cryptography. During flow allocation, the IRMd on the client side constructs an OAP (Ouroboros Allocation Protocol) header containing a unique flow ID, timestamp, and optionally the client&#039;s X.509 certificate, an ephemeral DHE public key, and a digital signature. This OAP header travels inside the FLOW_REQ message to the server&#039;s IRMd, which can verify the client&#039;s certificate against its configured CA trust store and validate the signature. The server&#039;s IRMd then responds with its own OAP header in the FLOW_REPLY, containing its certificate, ephemeral public key, and signature. Both sides independently derive the same symmetric encryption key using DHE key agreement. Once the flow is established, the library layer (between the application and IRMd) automatically encrypts outgoing data and decrypts incoming data using this shared key—the application&#039;s flow_read() and flow_write() calls work identically whether encryption is enabled or not. This architecture applies uniformly to all flows regardless of their QoS characteristics: whether the underlying flow provides reliable ordered delivery (connection-oriented semantics) or best-effort delivery (connectionless semantics), the security handshake occurs during flow allocation, and the resulting symmetric key protects all subsequent data exchange. The security policy is entirely configuration-driven through certificate and key files in security, allowing system administrators to enforce authentication and encryption requirements without any application code changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Client (IRMd)                              Server (IRMd)&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 1. Load client cert/key                   |&lt;br /&gt;
     | 2. Generate ephemeral keypair             |&lt;br /&gt;
     | 3. Build OAP_HDR (id, ts, crt, eph)       |&lt;br /&gt;
     | 4. Sign header with client key            |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |-------- FLOW_REQ (OAP_HDR) -------------&amp;gt; |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |                                           | 5. Load server cert/key&lt;br /&gt;
     |                                           | 6. Verify client cert against CA&lt;br /&gt;
     |                                           | 7. Verify client signature&lt;br /&gt;
     |                                           | 8. Generate ephemeral keypair&lt;br /&gt;
     |                                           | 9. Derive symmetric key (ECDHE)&lt;br /&gt;
     |                                           | 10. Build response OAP_HDR&lt;br /&gt;
     |                                           | 11. Sign with server key&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |&amp;lt;------- FLOW_REPLY (OAP_HDR) ------------ |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     | 12. Verify server cert against CA         |&lt;br /&gt;
     | 13. Verify server signature               |&lt;br /&gt;
     | 14. Derive symmetric key (ECDHE)          |&lt;br /&gt;
     |                                           |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
     |         Encrypted data channel            |&lt;br /&gt;
     |===========================================|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1878</id>
		<title>Definitions</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1878"/>
		<updated>2026-01-04T12:07:31Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Routing, Forwarding and Flooding */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Definitions: Flow, Routing, and Forwarding =&lt;br /&gt;
&lt;br /&gt;
This document contains formal definitions used in the Ouroboros architecture. The graph definitions follow Dieter Jungnickel&#039;s excellent &#039;&#039;Graph, Networks and Algorithms&#039;&#039;&amp;lt;ref&amp;gt;Jungnickel, D. (2007). Graphs, Networks and Algorithms.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Basic Graph Definitions ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;graph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, E)&amp;lt;/math&amp;gt; consisting of a set of &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; and a set of &#039;&#039;&#039;edges&#039;&#039;&#039; &amp;lt;math&amp;gt;E \subset V^2&amp;lt;/math&amp;gt; of two-element subsets of &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt;. An edge &amp;lt;math&amp;gt;e = (v_i,v_j)&amp;lt;/math&amp;gt; has (distinct) end vertices &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed graph&#039;&#039;&#039; or &#039;&#039;&#039;digraph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; consisting of a set &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; of vertices and a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of ordered pairs &amp;lt;math&amp;gt;(v_i, v_j)&amp;lt;/math&amp;gt; (called &#039;&#039;&#039;arcs&#039;&#039;&#039;) where &amp;lt;math&amp;gt;v_i \neq v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;network&#039;&#039;&#039; is a digraph &amp;lt;math&amp;gt;G = (V,A)&amp;lt;/math&amp;gt; on which a mapping &amp;lt;math&amp;gt;w: A \to \mathbb{R}&amp;lt;/math&amp;gt; from the edgeset to the reals is defined; the number &amp;lt;math&amp;gt;w(a)&amp;lt;/math&amp;gt; is called the &#039;&#039;&#039;weight&#039;&#039;&#039; of the arc &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;The weight of an edge is often called a &#039;&#039;metric&#039;&#039; in computer science literature (e.g. BGP metric). To avoid confusion, we use the term &#039;&#039;metric&#039;&#039; only in its mathematical meaning.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;a = (v_i,v_j) \in A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; is &#039;&#039;&#039;adjacent&#039;&#039;&#039; to &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt; and &#039;&#039;&#039;incident&#039;&#039;&#039; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. The set of &#039;&#039;&#039;neighbors&#039;&#039;&#039; &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; of a vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is the set of vertices that are adjacent to &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, where &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; contains all &amp;lt;math&amp;gt;u \in V&amp;lt;/math&amp;gt; such that &amp;lt;math&amp;gt;(v, u) \in A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Walks, Paths, and Cycles ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;walk&#039;&#039;&#039; is a sequence of vertices &amp;lt;math&amp;gt;\mathcal{W} = (v_0, v_1, \dots , v_n)&amp;lt;/math&amp;gt; so that &amp;lt;math&amp;gt;a_i = (v_{i-1},v_i) \in A , i = 1, \dots, n&amp;lt;/math&amp;gt;. So each walk also implies a sequence of edges. We define the weight of a walk &amp;lt;math&amp;gt;\mathcal{W}&amp;lt;/math&amp;gt; as the sum of the weights of its arcs, &amp;lt;math&amp;gt;w(\mathcal{W}) = \sum_{i=1}^n w(a_i)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;source&#039;&#039;&#039; &amp;lt;math&amp;gt;v_0&amp;lt;/math&amp;gt; and &#039;&#039;&#039;destination&#039;&#039;&#039; &amp;lt;math&amp;gt;v_n&amp;lt;/math&amp;gt; are the same (&amp;lt;math&amp;gt;v_0 = v_n&amp;lt;/math&amp;gt;), the walk is &#039;&#039;&#039;closed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A walk where each of the arcs &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; is distinct is called a &#039;&#039;&#039;trail&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;path&#039;&#039;&#039; is a trail for which each of the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;closed trail&#039;&#039;&#039; for which the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct is called a &#039;&#039;&#039;cycle&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;A &#039;&#039;Hamiltonian cycle&#039;&#039; is a special case of a closed walk that includes every vertex in the graph exactly once. This is necessarily also a closed trail.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed acyclic graph&#039;&#039;&#039; (DAG) is a digraph that does not contain any cycles.&lt;br /&gt;
&lt;br /&gt;
If for every pair of vertices &amp;lt;math&amp;gt;v_s, v_d \in V&amp;lt;/math&amp;gt; there is at least one path &amp;lt;math&amp;gt;\mathcal{P} = (v_s, \dots, v_d)&amp;lt;/math&amp;gt;, we call the (di)graph &#039;&#039;&#039;connected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Distance and Metrics ===&lt;br /&gt;
&lt;br /&gt;
The distance function defined by the weight of the shortest path between two vertices in a network (or &amp;lt;math&amp;gt;\infty&amp;lt;/math&amp;gt; if no such path exists) is called the &#039;&#039;geodesic&#039;&#039; distance.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metric&#039;&#039;&#039; is a (distance) function &amp;lt;math&amp;gt;d: X^2 \to [0, +\infty)&amp;lt;/math&amp;gt; fulfilling positivity, symmetry and triangle inequality:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x,y,z \in X: d(x, y) \geq 0 \land d(x,y) = d(y,x) \land d(x,z) \leq d(x,y) + d(y,z)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A geodesic distance is in general not a metric since it doesn&#039;t always fulfill the positivity and symmetry requirements in a digraph.&lt;br /&gt;
&lt;br /&gt;
== Routing, Forwarding and Flooding ==&lt;br /&gt;
&lt;br /&gt;
With routing we typically mean the process of selecting a path for traffic in a network. In computer science literature, there are two main groups of approaches to routing.&lt;br /&gt;
&lt;br /&gt;
On the one hand there are the &#039;&#039;&#039;hierarchical routing&#039;&#039;&#039; solutions. This is the approach taken in IP networks, where a set of subnetworks is defined using &#039;&#039;&#039;prefixes&#039;&#039;&#039; or &#039;&#039;&#039;subnet masks&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan.&amp;lt;/ref&amp;gt; A scalability issue with IP stems from not following the partial ordering implied by the subnetting in the delegation of IP addresses, causing fragmentation of the IP address space and making prefix aggregration in routers increasingly inefficient.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Rekhter&#039;s Law: Addressing can follow topology or topology can follow addressing. Choose one. RFC 4984.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the other hand we have &#039;&#039;&#039;geographic&#039;&#039;&#039; or &#039;&#039;&#039;geometric&#039;&#039;&#039; routing,&amp;lt;ref&amp;gt;Kuhn, F., Wattenhofer, R., and Zollinger, A. (2003). Worst-case optimal and average-case efficient geometric ad-hoc routing.&amp;lt;/ref&amp;gt; where each node is assigned a coordinate so next hops can be calculated making use of the coordinates of the direct neighbors.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Geographic coordinates are a compound name, consisting of latitudes and longitudes, but there is no order implied between these two coordinate spaces. Hence the partial ordering in our definition of an address.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The examples above illustrate that the concept of routing encompasses both the dissemination and gathering of information about the network, and the algorithms for calculation and selection of the paths. We will now define the concepts underpinning &amp;quot;routing&amp;quot; more formally. The reasoning behind it is similar to the reasoning commonly used in formulating (integer) linear programming solutions to problems in graph theory.&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; be a network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination vertices &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;, so that the following 4 conditions are met:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a directed acyclic subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only incoming arcs; and&lt;br /&gt;
# &amp;lt;math&amp;gt;A&#039; = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalently,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt; Proof of Equivalence: choose for &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; the length of the longest path between the corresponding vertices in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;.&amp;lt;/ref&amp;gt; &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(u, v_d) &amp;lt; d(v, v_d)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;\cup_{v \in V} H(v) = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, either the distance function bounds the routing solution, or the routing solution bounds the distance function.&lt;br /&gt;
&lt;br /&gt;
The formal definition says that a routing algorithm is equivalent a tree-like structure where every node along any valid path selects one or more neighbors that are strictly &amp;quot;closer&amp;quot; to the destination than itself. This structure can contain multiple paths from source to destination, allowing routing solution that move different packets (or fragments) along different routes through the network. The key guarantee is that all these paths always make progress toward their destination and can not contain (permanent) loops - think of it like water flowing downhill where it may split into multiple streams, but each stream always flows to a lower elevation and can never flow back uphill.&lt;br /&gt;
&lt;br /&gt;
This definition is very broad &amp;quot;one or more neighbors&amp;quot; selection allows solutions that send duplicates, erasure coding packet fragments etc.&lt;br /&gt;
&lt;br /&gt;
We define &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; as any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns the set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;. &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; is often implemented as &#039;&#039;&#039;ROUTING&#039;&#039;&#039; with an additional edge selection step.&lt;br /&gt;
&lt;br /&gt;
The necessary and sufficient condition for &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is full knowledge of the graph &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; and a valid geodesic distance &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. For a given vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, the necessary and sufficient set of information to obtain &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt; is knowledge of its neighbor set &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; and the subset of the geodesic distances originating at its neighbors, &amp;lt;math&amp;gt;d_{v} \subset d: N(v) \times V \to \mathbb{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In less formal terms, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; provide a set of vertices and arcs, respectively, so that there are never loops if one travels to a next vertex or along an arc in the set. If implemented in a centralized way, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; roughly need to know the full network. When implemented in a distributed way, a node roughly needs to know its neighbors and the distances to the destination from itself and from all its neighbors.&lt;br /&gt;
&lt;br /&gt;
The definitions above show what information needs to be disseminated in a network to allow &#039;&#039;&#039;FORWARDING&#039;&#039;&#039;. Let&#039;s assume that vertices know their neighbors or incident outgoing arcs, then what is needed is a dissemination procedure for the (geodesic) distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. This is implemented in a class of dissemination protocols, called &#039;&#039;&#039;link-state routing protocols&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors (with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;) so that:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a connected subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs.&lt;br /&gt;
&lt;br /&gt;
Equivalently, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(v_s, u) &amp;gt; d(v_s, v)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; creates a connected tree rooted at &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; that reaches all (reachable) vertices in the network. Each vertex selects neighbors that are strictly farther from the source than itself, ensuring the flood propagates outward without backtracking.&lt;br /&gt;
&lt;br /&gt;
== Flow ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;flow&#039;&#039;&#039; is the abstraction of a collection of resources within a network layer that allow bidirectional communications using packets between two processes that are clients of this layer. A flow enables a point-to-point &#039;&#039;&#039;packet delivery service&#039;&#039;&#039; and can be viewed as a bidirectional pipe that has a number of observable quantities associated with it that describe the probability &amp;lt;math&amp;gt;p(S,t, \ldots) \in [0, 1]&amp;lt;/math&amp;gt; of a packet of given size &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; being transferred within a certain period of time &amp;lt;math&amp;gt;[t_x, t_x + t]&amp;lt;/math&amp;gt;. The maximum probability for error-free transfer depends on the &#039;&#039;&#039;packet-drop-rate&#039;&#039;&#039; (PDR) and &#039;&#039;&#039;bit-error-rate&#039;&#039;&#039; (BER) of the flow.&lt;br /&gt;
&lt;br /&gt;
The Ouroboros architecture ensures that flows are &#039;&#039;&#039;content neutral&#039;&#039;&#039;, i.e. the probability &amp;lt;math&amp;gt;p(S, t, \ldots)&amp;lt;/math&amp;gt; above is independent of the bits that make up the packets sent along a flow.&lt;br /&gt;
&lt;br /&gt;
=== Flow Characteristics ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;delay&#039;&#039;&#039; or &#039;&#039;&#039;latency&#039;&#039;&#039; describes how long packets take to traverse the flow, and the variation on the delay is called &#039;&#039;&#039;jitter&#039;&#039;&#039;, or more precisely, &#039;&#039;&#039;packet delay variation&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 3393: IP Packet Delay Variation Metric for IP Performance Metrics (IPPM).&amp;lt;/ref&amp;gt; The delay for a flow has four main components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Propagation&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Queuing&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Transmission&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Processing&#039;&#039;&#039; delay&lt;br /&gt;
&lt;br /&gt;
=== Flow Bounds ===&lt;br /&gt;
&lt;br /&gt;
There are 2 upper bounds:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Lifetime&#039;&#039;&#039; (MPL) is the maximum amount of time that a packet can take to transfer over the flow&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Size&#039;&#039;&#039; (MPS) is the maximum length for a packet to be acceptable for transfer&lt;br /&gt;
&lt;br /&gt;
In other words, the probability for a packet to arrive after MPL expires should be close to 0,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;This may be hard to guarantee with 100 percent certainty, so MPL should be large enough so that this probability is 0 in practice. Ouroboros estimates MPL based on the Layer characteristics. IP has a bound on the Maximum Datagram Lifetime (MDL) via the Time-To-Live (v4) or Hop Limit (v6) decrement in each router to a maximum of 255 seconds (RFC 791), with a recommended value of 64 seconds (RFC 1700). In addition, TCP defines the Maximum Segment Lifetime (MSL) as 120s (RFC 793).&amp;lt;/ref&amp;gt; and the probability for a packet to arrive that exceeds the MPS is equal to 0.&lt;br /&gt;
&lt;br /&gt;
Similarly, there can be lower bounds such as Minimum Packet Lifetime (mPL) and Minimum Packet Size (mPS).&lt;br /&gt;
&lt;br /&gt;
=== Flow Resources ===&lt;br /&gt;
&lt;br /&gt;
The resources that make up a layer are finite, limiting the total number of packets that can traverse the network layer in a given period of time. Flows provide the mechanism to put a network layer fully in control of its own resources. The resources that constitute the flow can either be shared with other flows or dedicated (reserved) for this particular flow.&lt;br /&gt;
&lt;br /&gt;
Other externally measureable quantities can be associated with a flow, such as bandwidth and load for flows with reserved resources. The probability function may depend on these quantities (e.g. if the load reaches a certain threshold, delay could increase).&lt;br /&gt;
&lt;br /&gt;
=== Flow Identifiers ===&lt;br /&gt;
&lt;br /&gt;
A flow endpoint is identified in a system by a &#039;&#039;&#039;flow ID&#039;&#039;&#039; (FID), which defines the &#039;&#039;&#039;layer boundary&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;In this respect, a flow id is similar to an OSI &#039;&#039;&#039;Service Access Point&#039;&#039;&#039; (SAP) or RINA &#039;&#039;&#039;port id&#039;&#039;&#039;.&amp;lt;/ref&amp;gt;. For security reasons, a process has no direct access to the flow, but rather accesses the flow through a &#039;&#039;&#039;Flow Descriptor&#039;&#039;&#039; (FD) to read and write from a flow. Flow identifiers are unique within the scope of a system, flow descriptors are unique within the scope of a process&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;This is similar in function to a UNIX file descriptor.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Flows are an important concept for enabling Quality-of-Service (QoS) in a layer.&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references group=&amp;quot;note&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1877</id>
		<title>Definitions</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1877"/>
		<updated>2026-01-04T12:05:03Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Flow Identifiers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Definitions: Flow, Routing, and Forwarding =&lt;br /&gt;
&lt;br /&gt;
This document contains formal definitions used in the Ouroboros architecture. The graph definitions follow Dieter Jungnickel&#039;s excellent &#039;&#039;Graph, Networks and Algorithms&#039;&#039;&amp;lt;ref&amp;gt;Jungnickel, D. (2007). Graphs, Networks and Algorithms.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Basic Graph Definitions ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;graph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, E)&amp;lt;/math&amp;gt; consisting of a set of &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; and a set of &#039;&#039;&#039;edges&#039;&#039;&#039; &amp;lt;math&amp;gt;E \subset V^2&amp;lt;/math&amp;gt; of two-element subsets of &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt;. An edge &amp;lt;math&amp;gt;e = (v_i,v_j)&amp;lt;/math&amp;gt; has (distinct) end vertices &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed graph&#039;&#039;&#039; or &#039;&#039;&#039;digraph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; consisting of a set &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; of vertices and a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of ordered pairs &amp;lt;math&amp;gt;(v_i, v_j)&amp;lt;/math&amp;gt; (called &#039;&#039;&#039;arcs&#039;&#039;&#039;) where &amp;lt;math&amp;gt;v_i \neq v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;network&#039;&#039;&#039; is a digraph &amp;lt;math&amp;gt;G = (V,A)&amp;lt;/math&amp;gt; on which a mapping &amp;lt;math&amp;gt;w: A \to \mathbb{R}&amp;lt;/math&amp;gt; from the edgeset to the reals is defined; the number &amp;lt;math&amp;gt;w(a)&amp;lt;/math&amp;gt; is called the &#039;&#039;&#039;weight&#039;&#039;&#039; of the arc &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;The weight of an edge is often called a &#039;&#039;metric&#039;&#039; in computer science literature (e.g. BGP metric). To avoid confusion, we use the term &#039;&#039;metric&#039;&#039; only in its mathematical meaning.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;a = (v_i,v_j) \in A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; is &#039;&#039;&#039;adjacent&#039;&#039;&#039; to &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt; and &#039;&#039;&#039;incident&#039;&#039;&#039; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. The set of &#039;&#039;&#039;neighbors&#039;&#039;&#039; &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; of a vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is the set of vertices that are adjacent to &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, where &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; contains all &amp;lt;math&amp;gt;u \in V&amp;lt;/math&amp;gt; such that &amp;lt;math&amp;gt;(v, u) \in A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Walks, Paths, and Cycles ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;walk&#039;&#039;&#039; is a sequence of vertices &amp;lt;math&amp;gt;\mathcal{W} = (v_0, v_1, \dots , v_n)&amp;lt;/math&amp;gt; so that &amp;lt;math&amp;gt;a_i = (v_{i-1},v_i) \in A , i = 1, \dots, n&amp;lt;/math&amp;gt;. So each walk also implies a sequence of edges. We define the weight of a walk &amp;lt;math&amp;gt;\mathcal{W}&amp;lt;/math&amp;gt; as the sum of the weights of its arcs, &amp;lt;math&amp;gt;w(\mathcal{W}) = \sum_{i=1}^n w(a_i)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;source&#039;&#039;&#039; &amp;lt;math&amp;gt;v_0&amp;lt;/math&amp;gt; and &#039;&#039;&#039;destination&#039;&#039;&#039; &amp;lt;math&amp;gt;v_n&amp;lt;/math&amp;gt; are the same (&amp;lt;math&amp;gt;v_0 = v_n&amp;lt;/math&amp;gt;), the walk is &#039;&#039;&#039;closed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A walk where each of the arcs &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; is distinct is called a &#039;&#039;&#039;trail&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;path&#039;&#039;&#039; is a trail for which each of the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;closed trail&#039;&#039;&#039; for which the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct is called a &#039;&#039;&#039;cycle&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;A &#039;&#039;Hamiltonian cycle&#039;&#039; is a special case of a closed walk that includes every vertex in the graph exactly once. This is necessarily also a closed trail.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed acyclic graph&#039;&#039;&#039; (DAG) is a digraph that does not contain any cycles.&lt;br /&gt;
&lt;br /&gt;
If for every pair of vertices &amp;lt;math&amp;gt;v_s, v_d \in V&amp;lt;/math&amp;gt; there is at least one path &amp;lt;math&amp;gt;\mathcal{P} = (v_s, \dots, v_d)&amp;lt;/math&amp;gt;, we call the (di)graph &#039;&#039;&#039;connected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Distance and Metrics ===&lt;br /&gt;
&lt;br /&gt;
The distance function defined by the weight of the shortest path between two vertices in a network (or &amp;lt;math&amp;gt;\infty&amp;lt;/math&amp;gt; if no such path exists) is called the &#039;&#039;geodesic&#039;&#039; distance.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metric&#039;&#039;&#039; is a (distance) function &amp;lt;math&amp;gt;d: X^2 \to [0, +\infty)&amp;lt;/math&amp;gt; fulfilling positivity, symmetry and triangle inequality:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x,y,z \in X: d(x, y) \geq 0 \land d(x,y) = d(y,x) \land d(x,z) \leq d(x,y) + d(y,z)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A geodesic distance is in general not a metric since it doesn&#039;t always fulfill the positivity and symmetry requirements in a digraph.&lt;br /&gt;
&lt;br /&gt;
== Routing, Forwarding and Flooding ==&lt;br /&gt;
&lt;br /&gt;
With routing we typically mean the process of selecting a path for traffic in a network. In computer science literature, there are two main groups of approaches to routing.&lt;br /&gt;
&lt;br /&gt;
On the one hand there are the &#039;&#039;&#039;hierarchical routing&#039;&#039;&#039; solutions. This is the approach taken in IP networks, where a set of subnetworks is defined using &#039;&#039;&#039;prefixes&#039;&#039;&#039; or &#039;&#039;&#039;subnet masks&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan.&amp;lt;/ref&amp;gt; A scalability issue with IP stems from not following the partial ordering implied by the subnetting in the delegation of IP addresses, causing fragmentation of the IP address space and making prefix aggregration in routers increasingly inefficient.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Rekhter&#039;s Law: Addressing can follow topology or topology can follow addressing. Choose one. RFC 4984.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the other hand we have &#039;&#039;&#039;geographic&#039;&#039;&#039; or &#039;&#039;&#039;geometric&#039;&#039;&#039; routing,&amp;lt;ref&amp;gt;Kuhn, F., Wattenhofer, R., and Zollinger, A. (2003). Worst-case optimal and average-case efficient geometric ad-hoc routing.&amp;lt;/ref&amp;gt; where each node is assigned a coordinate so next hops can be calculated making use of the coordinates of the direct neighbors.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Geographic coordinates are a compound name, consisting of latitudes and longitudes, but there is no order implied between these two coordinate spaces. Hence the partial ordering in our definition of an address.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The examples above illustrate that the concept of routing encompasses both the dissemination and gathering of information about the network, and the algorithms for calculation and selection of the paths. We will now define the concepts underpinning &amp;quot;routing&amp;quot; more formally. The reasoning behind it is similar to the reasoning commonly used in formulating (integer) linear programming solutions to problems in graph theory.&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; be a network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination vertices &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;, so that the following 4 conditions are met:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a directed acyclic subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only incoming arcs; and&lt;br /&gt;
# &amp;lt;math&amp;gt;A&#039; = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalently,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt; Proof of Equivalence: choose for &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; the length of the longest path between the corresponding vertices in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;. This also proves it covers &#039;&#039;all&#039;&#039; algorithms, unless you find a path longer than the longest path...&amp;lt;/ref&amp;gt; &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(u, v_d) &amp;lt; d(v, v_d)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;\cup_{v \in V} H(v) = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, either the distance function bounds the routing solution, or the routing solution bounds the distance function.&lt;br /&gt;
&lt;br /&gt;
The formal definition says that a routing algorithm is equivalent a tree-like structure where every node along any valid path selects one or more neighbors that are strictly &amp;quot;closer&amp;quot; to the destination than itself. This structure can contain multiple paths from source to destination, allowing routing solution that move different packets (or fragments) along different routes through the network. The key guarantee is that all these paths always make progress toward their destination and can not contain (permanent) loops - think of it like water flowing downhill where it may split into multiple streams, but each stream always flows to a lower elevation and can never flow back uphill.&lt;br /&gt;
&lt;br /&gt;
This definition is very broad &amp;quot;one or more neighbors&amp;quot; selection allows solutions that send duplicates, erasure coding packet fragments etc.&lt;br /&gt;
&lt;br /&gt;
We define &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; as any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns the set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;. &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; is often implemented as &#039;&#039;&#039;ROUTING&#039;&#039;&#039; with an additional edge selection step.&lt;br /&gt;
&lt;br /&gt;
The necessary and sufficient condition for &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is full knowledge of the graph &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; and a valid geodesic distance &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. For a given vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, the necessary and sufficient set of information to obtain &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt; is knowledge of its neighbor set &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; and the subset of the geodesic distances originating at its neighbors, &amp;lt;math&amp;gt;d_{v} \subset d: N(v) \times V \to \mathbb{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In less formal terms, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; provide a set of vertices and arcs, respectively, so that there are never loops if one travels to a next vertex or along an arc in the set. If implemented in a centralized way, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; roughly need to know the full network. When implemented in a distributed way, a node roughly needs to know its neighbors and the distances to the destination from itself and from all its neighbors.&lt;br /&gt;
&lt;br /&gt;
The definitions above show what information needs to be disseminated in a network to allow &#039;&#039;&#039;FORWARDING&#039;&#039;&#039;. Let&#039;s assume that vertices know their neighbors or incident outgoing arcs, then what is needed is a dissemination procedure for the (geodesic) distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. This is implemented in a class of dissemination protocols, called &#039;&#039;&#039;link-state routing protocols&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors (with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;) so that:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a connected subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs.&lt;br /&gt;
&lt;br /&gt;
Equivalently, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(v_s, u) &amp;gt; d(v_s, v)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; creates a connected tree rooted at &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; that reaches all (reachable) vertices in the network. Each vertex selects neighbors that are strictly farther from the source than itself, ensuring the flood propagates outward without backtracking.&lt;br /&gt;
&lt;br /&gt;
== Flow ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;flow&#039;&#039;&#039; is the abstraction of a collection of resources within a network layer that allow bidirectional communications using packets between two processes that are clients of this layer. A flow enables a point-to-point &#039;&#039;&#039;packet delivery service&#039;&#039;&#039; and can be viewed as a bidirectional pipe that has a number of observable quantities associated with it that describe the probability &amp;lt;math&amp;gt;p(S,t, \ldots) \in [0, 1]&amp;lt;/math&amp;gt; of a packet of given size &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; being transferred within a certain period of time &amp;lt;math&amp;gt;[t_x, t_x + t]&amp;lt;/math&amp;gt;. The maximum probability for error-free transfer depends on the &#039;&#039;&#039;packet-drop-rate&#039;&#039;&#039; (PDR) and &#039;&#039;&#039;bit-error-rate&#039;&#039;&#039; (BER) of the flow.&lt;br /&gt;
&lt;br /&gt;
The Ouroboros architecture ensures that flows are &#039;&#039;&#039;content neutral&#039;&#039;&#039;, i.e. the probability &amp;lt;math&amp;gt;p(S, t, \ldots)&amp;lt;/math&amp;gt; above is independent of the bits that make up the packets sent along a flow.&lt;br /&gt;
&lt;br /&gt;
=== Flow Characteristics ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;delay&#039;&#039;&#039; or &#039;&#039;&#039;latency&#039;&#039;&#039; describes how long packets take to traverse the flow, and the variation on the delay is called &#039;&#039;&#039;jitter&#039;&#039;&#039;, or more precisely, &#039;&#039;&#039;packet delay variation&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 3393: IP Packet Delay Variation Metric for IP Performance Metrics (IPPM).&amp;lt;/ref&amp;gt; The delay for a flow has four main components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Propagation&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Queuing&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Transmission&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Processing&#039;&#039;&#039; delay&lt;br /&gt;
&lt;br /&gt;
=== Flow Bounds ===&lt;br /&gt;
&lt;br /&gt;
There are 2 upper bounds:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Lifetime&#039;&#039;&#039; (MPL) is the maximum amount of time that a packet can take to transfer over the flow&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Size&#039;&#039;&#039; (MPS) is the maximum length for a packet to be acceptable for transfer&lt;br /&gt;
&lt;br /&gt;
In other words, the probability for a packet to arrive after MPL expires should be close to 0,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;This may be hard to guarantee with 100 percent certainty, so MPL should be large enough so that this probability is 0 in practice. Ouroboros estimates MPL based on the Layer characteristics. IP has a bound on the Maximum Datagram Lifetime (MDL) via the Time-To-Live (v4) or Hop Limit (v6) decrement in each router to a maximum of 255 seconds (RFC 791), with a recommended value of 64 seconds (RFC 1700). In addition, TCP defines the Maximum Segment Lifetime (MSL) as 120s (RFC 793).&amp;lt;/ref&amp;gt; and the probability for a packet to arrive that exceeds the MPS is equal to 0.&lt;br /&gt;
&lt;br /&gt;
Similarly, there can be lower bounds such as Minimum Packet Lifetime (mPL) and Minimum Packet Size (mPS).&lt;br /&gt;
&lt;br /&gt;
=== Flow Resources ===&lt;br /&gt;
&lt;br /&gt;
The resources that make up a layer are finite, limiting the total number of packets that can traverse the network layer in a given period of time. Flows provide the mechanism to put a network layer fully in control of its own resources. The resources that constitute the flow can either be shared with other flows or dedicated (reserved) for this particular flow.&lt;br /&gt;
&lt;br /&gt;
Other externally measureable quantities can be associated with a flow, such as bandwidth and load for flows with reserved resources. The probability function may depend on these quantities (e.g. if the load reaches a certain threshold, delay could increase).&lt;br /&gt;
&lt;br /&gt;
=== Flow Identifiers ===&lt;br /&gt;
&lt;br /&gt;
A flow endpoint is identified in a system by a &#039;&#039;&#039;flow ID&#039;&#039;&#039; (FID), which defines the &#039;&#039;&#039;layer boundary&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;In this respect, a flow id is similar to an OSI &#039;&#039;&#039;Service Access Point&#039;&#039;&#039; (SAP) or RINA &#039;&#039;&#039;port id&#039;&#039;&#039;.&amp;lt;/ref&amp;gt;. For security reasons, a process has no direct access to the flow, but rather accesses the flow through a &#039;&#039;&#039;Flow Descriptor&#039;&#039;&#039; (FD) to read and write from a flow. Flow identifiers are unique within the scope of a system, flow descriptors are unique within the scope of a process&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;This is similar in function to a UNIX file descriptor.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Flows are an important concept for enabling Quality-of-Service (QoS) in a layer.&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references group=&amp;quot;note&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1876</id>
		<title>Definitions</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1876"/>
		<updated>2026-01-04T12:01:30Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Flow */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Definitions: Flow, Routing, and Forwarding =&lt;br /&gt;
&lt;br /&gt;
This document contains formal definitions used in the Ouroboros architecture. The graph definitions follow Dieter Jungnickel&#039;s excellent &#039;&#039;Graph, Networks and Algorithms&#039;&#039;&amp;lt;ref&amp;gt;Jungnickel, D. (2007). Graphs, Networks and Algorithms.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Basic Graph Definitions ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;graph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, E)&amp;lt;/math&amp;gt; consisting of a set of &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; and a set of &#039;&#039;&#039;edges&#039;&#039;&#039; &amp;lt;math&amp;gt;E \subset V^2&amp;lt;/math&amp;gt; of two-element subsets of &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt;. An edge &amp;lt;math&amp;gt;e = (v_i,v_j)&amp;lt;/math&amp;gt; has (distinct) end vertices &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed graph&#039;&#039;&#039; or &#039;&#039;&#039;digraph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; consisting of a set &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; of vertices and a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of ordered pairs &amp;lt;math&amp;gt;(v_i, v_j)&amp;lt;/math&amp;gt; (called &#039;&#039;&#039;arcs&#039;&#039;&#039;) where &amp;lt;math&amp;gt;v_i \neq v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;network&#039;&#039;&#039; is a digraph &amp;lt;math&amp;gt;G = (V,A)&amp;lt;/math&amp;gt; on which a mapping &amp;lt;math&amp;gt;w: A \to \mathbb{R}&amp;lt;/math&amp;gt; from the edgeset to the reals is defined; the number &amp;lt;math&amp;gt;w(a)&amp;lt;/math&amp;gt; is called the &#039;&#039;&#039;weight&#039;&#039;&#039; of the arc &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;The weight of an edge is often called a &#039;&#039;metric&#039;&#039; in computer science literature (e.g. BGP metric). To avoid confusion, we use the term &#039;&#039;metric&#039;&#039; only in its mathematical meaning.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;a = (v_i,v_j) \in A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; is &#039;&#039;&#039;adjacent&#039;&#039;&#039; to &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt; and &#039;&#039;&#039;incident&#039;&#039;&#039; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. The set of &#039;&#039;&#039;neighbors&#039;&#039;&#039; &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; of a vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is the set of vertices that are adjacent to &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, where &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; contains all &amp;lt;math&amp;gt;u \in V&amp;lt;/math&amp;gt; such that &amp;lt;math&amp;gt;(v, u) \in A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Walks, Paths, and Cycles ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;walk&#039;&#039;&#039; is a sequence of vertices &amp;lt;math&amp;gt;\mathcal{W} = (v_0, v_1, \dots , v_n)&amp;lt;/math&amp;gt; so that &amp;lt;math&amp;gt;a_i = (v_{i-1},v_i) \in A , i = 1, \dots, n&amp;lt;/math&amp;gt;. So each walk also implies a sequence of edges. We define the weight of a walk &amp;lt;math&amp;gt;\mathcal{W}&amp;lt;/math&amp;gt; as the sum of the weights of its arcs, &amp;lt;math&amp;gt;w(\mathcal{W}) = \sum_{i=1}^n w(a_i)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;source&#039;&#039;&#039; &amp;lt;math&amp;gt;v_0&amp;lt;/math&amp;gt; and &#039;&#039;&#039;destination&#039;&#039;&#039; &amp;lt;math&amp;gt;v_n&amp;lt;/math&amp;gt; are the same (&amp;lt;math&amp;gt;v_0 = v_n&amp;lt;/math&amp;gt;), the walk is &#039;&#039;&#039;closed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A walk where each of the arcs &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; is distinct is called a &#039;&#039;&#039;trail&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;path&#039;&#039;&#039; is a trail for which each of the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;closed trail&#039;&#039;&#039; for which the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct is called a &#039;&#039;&#039;cycle&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;A &#039;&#039;Hamiltonian cycle&#039;&#039; is a special case of a closed walk that includes every vertex in the graph exactly once. This is necessarily also a closed trail.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed acyclic graph&#039;&#039;&#039; (DAG) is a digraph that does not contain any cycles.&lt;br /&gt;
&lt;br /&gt;
If for every pair of vertices &amp;lt;math&amp;gt;v_s, v_d \in V&amp;lt;/math&amp;gt; there is at least one path &amp;lt;math&amp;gt;\mathcal{P} = (v_s, \dots, v_d)&amp;lt;/math&amp;gt;, we call the (di)graph &#039;&#039;&#039;connected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Distance and Metrics ===&lt;br /&gt;
&lt;br /&gt;
The distance function defined by the weight of the shortest path between two vertices in a network (or &amp;lt;math&amp;gt;\infty&amp;lt;/math&amp;gt; if no such path exists) is called the &#039;&#039;geodesic&#039;&#039; distance.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metric&#039;&#039;&#039; is a (distance) function &amp;lt;math&amp;gt;d: X^2 \to [0, +\infty)&amp;lt;/math&amp;gt; fulfilling positivity, symmetry and triangle inequality:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x,y,z \in X: d(x, y) \geq 0 \land d(x,y) = d(y,x) \land d(x,z) \leq d(x,y) + d(y,z)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A geodesic distance is in general not a metric since it doesn&#039;t always fulfill the positivity and symmetry requirements in a digraph.&lt;br /&gt;
&lt;br /&gt;
== Routing, Forwarding and Flooding ==&lt;br /&gt;
&lt;br /&gt;
With routing we typically mean the process of selecting a path for traffic in a network. In computer science literature, there are two main groups of approaches to routing.&lt;br /&gt;
&lt;br /&gt;
On the one hand there are the &#039;&#039;&#039;hierarchical routing&#039;&#039;&#039; solutions. This is the approach taken in IP networks, where a set of subnetworks is defined using &#039;&#039;&#039;prefixes&#039;&#039;&#039; or &#039;&#039;&#039;subnet masks&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan.&amp;lt;/ref&amp;gt; A scalability issue with IP stems from not following the partial ordering implied by the subnetting in the delegation of IP addresses, causing fragmentation of the IP address space and making prefix aggregration in routers increasingly inefficient.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Rekhter&#039;s Law: Addressing can follow topology or topology can follow addressing. Choose one. RFC 4984.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the other hand we have &#039;&#039;&#039;geographic&#039;&#039;&#039; or &#039;&#039;&#039;geometric&#039;&#039;&#039; routing,&amp;lt;ref&amp;gt;Kuhn, F., Wattenhofer, R., and Zollinger, A. (2003). Worst-case optimal and average-case efficient geometric ad-hoc routing.&amp;lt;/ref&amp;gt; where each node is assigned a coordinate so next hops can be calculated making use of the coordinates of the direct neighbors.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Geographic coordinates are a compound name, consisting of latitudes and longitudes, but there is no order implied between these two coordinate spaces. Hence the partial ordering in our definition of an address.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The examples above illustrate that the concept of routing encompasses both the dissemination and gathering of information about the network, and the algorithms for calculation and selection of the paths. We will now define the concepts underpinning &amp;quot;routing&amp;quot; more formally. The reasoning behind it is similar to the reasoning commonly used in formulating (integer) linear programming solutions to problems in graph theory.&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; be a network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination vertices &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;, so that the following 4 conditions are met:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a directed acyclic subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only incoming arcs; and&lt;br /&gt;
# &amp;lt;math&amp;gt;A&#039; = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalently,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt; Proof of Equivalence: choose for &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; the length of the longest path between the corresponding vertices in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;. This also proves it covers &#039;&#039;all&#039;&#039; algorithms, unless you find a path longer than the longest path...&amp;lt;/ref&amp;gt; &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(u, v_d) &amp;lt; d(v, v_d)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;\cup_{v \in V} H(v) = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, either the distance function bounds the routing solution, or the routing solution bounds the distance function.&lt;br /&gt;
&lt;br /&gt;
The formal definition says that a routing algorithm is equivalent a tree-like structure where every node along any valid path selects one or more neighbors that are strictly &amp;quot;closer&amp;quot; to the destination than itself. This structure can contain multiple paths from source to destination, allowing routing solution that move different packets (or fragments) along different routes through the network. The key guarantee is that all these paths always make progress toward their destination and can not contain (permanent) loops - think of it like water flowing downhill where it may split into multiple streams, but each stream always flows to a lower elevation and can never flow back uphill.&lt;br /&gt;
&lt;br /&gt;
This definition is very broad &amp;quot;one or more neighbors&amp;quot; selection allows solutions that send duplicates, erasure coding packet fragments etc.&lt;br /&gt;
&lt;br /&gt;
We define &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; as any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns the set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;. &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; is often implemented as &#039;&#039;&#039;ROUTING&#039;&#039;&#039; with an additional edge selection step.&lt;br /&gt;
&lt;br /&gt;
The necessary and sufficient condition for &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is full knowledge of the graph &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; and a valid geodesic distance &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. For a given vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, the necessary and sufficient set of information to obtain &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt; is knowledge of its neighbor set &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; and the subset of the geodesic distances originating at its neighbors, &amp;lt;math&amp;gt;d_{v} \subset d: N(v) \times V \to \mathbb{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In less formal terms, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; provide a set of vertices and arcs, respectively, so that there are never loops if one travels to a next vertex or along an arc in the set. If implemented in a centralized way, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; roughly need to know the full network. When implemented in a distributed way, a node roughly needs to know its neighbors and the distances to the destination from itself and from all its neighbors.&lt;br /&gt;
&lt;br /&gt;
The definitions above show what information needs to be disseminated in a network to allow &#039;&#039;&#039;FORWARDING&#039;&#039;&#039;. Let&#039;s assume that vertices know their neighbors or incident outgoing arcs, then what is needed is a dissemination procedure for the (geodesic) distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. This is implemented in a class of dissemination protocols, called &#039;&#039;&#039;link-state routing protocols&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors (with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;) so that:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a connected subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs.&lt;br /&gt;
&lt;br /&gt;
Equivalently, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(v_s, u) &amp;gt; d(v_s, v)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; creates a connected tree rooted at &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; that reaches all (reachable) vertices in the network. Each vertex selects neighbors that are strictly farther from the source than itself, ensuring the flood propagates outward without backtracking.&lt;br /&gt;
&lt;br /&gt;
== Flow ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;flow&#039;&#039;&#039; is the abstraction of a collection of resources within a network layer that allow bidirectional communications using packets between two processes that are clients of this layer. A flow enables a point-to-point &#039;&#039;&#039;packet delivery service&#039;&#039;&#039; and can be viewed as a bidirectional pipe that has a number of observable quantities associated with it that describe the probability &amp;lt;math&amp;gt;p(S,t, \ldots) \in [0, 1]&amp;lt;/math&amp;gt; of a packet of given size &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; being transferred within a certain period of time &amp;lt;math&amp;gt;[t_x, t_x + t]&amp;lt;/math&amp;gt;. The maximum probability for error-free transfer depends on the &#039;&#039;&#039;packet-drop-rate&#039;&#039;&#039; (PDR) and &#039;&#039;&#039;bit-error-rate&#039;&#039;&#039; (BER) of the flow.&lt;br /&gt;
&lt;br /&gt;
The Ouroboros architecture ensures that flows are &#039;&#039;&#039;content neutral&#039;&#039;&#039;, i.e. the probability &amp;lt;math&amp;gt;p(S, t, \ldots)&amp;lt;/math&amp;gt; above is independent of the bits that make up the packets sent along a flow.&lt;br /&gt;
&lt;br /&gt;
=== Flow Characteristics ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;delay&#039;&#039;&#039; or &#039;&#039;&#039;latency&#039;&#039;&#039; describes how long packets take to traverse the flow, and the variation on the delay is called &#039;&#039;&#039;jitter&#039;&#039;&#039;, or more precisely, &#039;&#039;&#039;packet delay variation&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 3393: IP Packet Delay Variation Metric for IP Performance Metrics (IPPM).&amp;lt;/ref&amp;gt; The delay for a flow has four main components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Propagation&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Queuing&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Transmission&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Processing&#039;&#039;&#039; delay&lt;br /&gt;
&lt;br /&gt;
=== Flow Bounds ===&lt;br /&gt;
&lt;br /&gt;
There are 2 upper bounds:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Lifetime&#039;&#039;&#039; (MPL) is the maximum amount of time that a packet can take to transfer over the flow&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Size&#039;&#039;&#039; (MPS) is the maximum length for a packet to be acceptable for transfer&lt;br /&gt;
&lt;br /&gt;
In other words, the probability for a packet to arrive after MPL expires should be close to 0,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;This may be hard to guarantee with 100 percent certainty, so MPL should be large enough so that this probability is 0 in practice. Ouroboros estimates MPL based on the Layer characteristics. IP has a bound on the Maximum Datagram Lifetime (MDL) via the Time-To-Live (v4) or Hop Limit (v6) decrement in each router to a maximum of 255 seconds (RFC 791), with a recommended value of 64 seconds (RFC 1700). In addition, TCP defines the Maximum Segment Lifetime (MSL) as 120s (RFC 793).&amp;lt;/ref&amp;gt; and the probability for a packet to arrive that exceeds the MPS is equal to 0.&lt;br /&gt;
&lt;br /&gt;
Similarly, there can be lower bounds such as Minimum Packet Lifetime (mPL) and Minimum Packet Size (mPS).&lt;br /&gt;
&lt;br /&gt;
=== Flow Resources ===&lt;br /&gt;
&lt;br /&gt;
The resources that make up a layer are finite, limiting the total number of packets that can traverse the network layer in a given period of time. Flows provide the mechanism to put a network layer fully in control of its own resources. The resources that constitute the flow can either be shared with other flows or dedicated (reserved) for this particular flow.&lt;br /&gt;
&lt;br /&gt;
Other externally measureable quantities can be associated with a flow, such as bandwidth and load for flows with reserved resources. The probability function may depend on these quantities (e.g. if the load reaches a certain threshold, delay could increase).&lt;br /&gt;
&lt;br /&gt;
=== Flow Identifiers ===&lt;br /&gt;
&lt;br /&gt;
A flow endpoint is identified in a system by a &#039;&#039;&#039;flow ID&#039;&#039;&#039; (FID), which defines the &#039;&#039;&#039;layer boundary&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;In this respect, a flow id is similar to an OSI &#039;&#039;&#039;Service Access Point&#039;&#039;&#039; (SAP) or RINA &#039;&#039;&#039;port id&#039;&#039;&#039;.&amp;lt;/ref&amp;gt;. For security reasons, a process has no direct access to the flow, but rather accesses the flow through a &#039;&#039;&#039;Flow Descriptor&#039;&#039;&#039; (FD) to read and write from a flow. Flow identifiers are unique within the scope of a system, flow descriptors are unique within the scope of a process&amp;lt;ref&amp;gt;This is similar in function to a UNIX file descriptor. A UNIX kernel space implementation of Ouroboros would probably use file descriptors for flow descriptors.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Flows are an important concept for enabling Quality-of-Service (QoS) in a layer.&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references group=&amp;quot;note&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1875</id>
		<title>Definitions</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1875"/>
		<updated>2026-01-04T11:33:16Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Routing, Forwarding and Flooding */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Definitions: Flow, Routing, and Forwarding =&lt;br /&gt;
&lt;br /&gt;
This document contains formal definitions used in the Ouroboros architecture. The graph definitions follow Dieter Jungnickel&#039;s excellent &#039;&#039;Graph, Networks and Algorithms&#039;&#039;&amp;lt;ref&amp;gt;Jungnickel, D. (2007). Graphs, Networks and Algorithms.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Basic Graph Definitions ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;graph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, E)&amp;lt;/math&amp;gt; consisting of a set of &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; and a set of &#039;&#039;&#039;edges&#039;&#039;&#039; &amp;lt;math&amp;gt;E \subset V^2&amp;lt;/math&amp;gt; of two-element subsets of &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt;. An edge &amp;lt;math&amp;gt;e = (v_i,v_j)&amp;lt;/math&amp;gt; has (distinct) end vertices &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed graph&#039;&#039;&#039; or &#039;&#039;&#039;digraph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; consisting of a set &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; of vertices and a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of ordered pairs &amp;lt;math&amp;gt;(v_i, v_j)&amp;lt;/math&amp;gt; (called &#039;&#039;&#039;arcs&#039;&#039;&#039;) where &amp;lt;math&amp;gt;v_i \neq v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;network&#039;&#039;&#039; is a digraph &amp;lt;math&amp;gt;G = (V,A)&amp;lt;/math&amp;gt; on which a mapping &amp;lt;math&amp;gt;w: A \to \mathbb{R}&amp;lt;/math&amp;gt; from the edgeset to the reals is defined; the number &amp;lt;math&amp;gt;w(a)&amp;lt;/math&amp;gt; is called the &#039;&#039;&#039;weight&#039;&#039;&#039; of the arc &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;The weight of an edge is often called a &#039;&#039;metric&#039;&#039; in computer science literature (e.g. BGP metric). To avoid confusion, we use the term &#039;&#039;metric&#039;&#039; only in its mathematical meaning.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;a = (v_i,v_j) \in A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; is &#039;&#039;&#039;adjacent&#039;&#039;&#039; to &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt; and &#039;&#039;&#039;incident&#039;&#039;&#039; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. The set of &#039;&#039;&#039;neighbors&#039;&#039;&#039; &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; of a vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is the set of vertices that are adjacent to &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, where &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; contains all &amp;lt;math&amp;gt;u \in V&amp;lt;/math&amp;gt; such that &amp;lt;math&amp;gt;(v, u) \in A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Walks, Paths, and Cycles ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;walk&#039;&#039;&#039; is a sequence of vertices &amp;lt;math&amp;gt;\mathcal{W} = (v_0, v_1, \dots , v_n)&amp;lt;/math&amp;gt; so that &amp;lt;math&amp;gt;a_i = (v_{i-1},v_i) \in A , i = 1, \dots, n&amp;lt;/math&amp;gt;. So each walk also implies a sequence of edges. We define the weight of a walk &amp;lt;math&amp;gt;\mathcal{W}&amp;lt;/math&amp;gt; as the sum of the weights of its arcs, &amp;lt;math&amp;gt;w(\mathcal{W}) = \sum_{i=1}^n w(a_i)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;source&#039;&#039;&#039; &amp;lt;math&amp;gt;v_0&amp;lt;/math&amp;gt; and &#039;&#039;&#039;destination&#039;&#039;&#039; &amp;lt;math&amp;gt;v_n&amp;lt;/math&amp;gt; are the same (&amp;lt;math&amp;gt;v_0 = v_n&amp;lt;/math&amp;gt;), the walk is &#039;&#039;&#039;closed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A walk where each of the arcs &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; is distinct is called a &#039;&#039;&#039;trail&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;path&#039;&#039;&#039; is a trail for which each of the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;closed trail&#039;&#039;&#039; for which the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct is called a &#039;&#039;&#039;cycle&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;A &#039;&#039;Hamiltonian cycle&#039;&#039; is a special case of a closed walk that includes every vertex in the graph exactly once. This is necessarily also a closed trail.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed acyclic graph&#039;&#039;&#039; (DAG) is a digraph that does not contain any cycles.&lt;br /&gt;
&lt;br /&gt;
If for every pair of vertices &amp;lt;math&amp;gt;v_s, v_d \in V&amp;lt;/math&amp;gt; there is at least one path &amp;lt;math&amp;gt;\mathcal{P} = (v_s, \dots, v_d)&amp;lt;/math&amp;gt;, we call the (di)graph &#039;&#039;&#039;connected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Distance and Metrics ===&lt;br /&gt;
&lt;br /&gt;
The distance function defined by the weight of the shortest path between two vertices in a network (or &amp;lt;math&amp;gt;\infty&amp;lt;/math&amp;gt; if no such path exists) is called the &#039;&#039;geodesic&#039;&#039; distance.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metric&#039;&#039;&#039; is a (distance) function &amp;lt;math&amp;gt;d: X^2 \to [0, +\infty)&amp;lt;/math&amp;gt; fulfilling positivity, symmetry and triangle inequality:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x,y,z \in X: d(x, y) \geq 0 \land d(x,y) = d(y,x) \land d(x,z) \leq d(x,y) + d(y,z)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A geodesic distance is in general not a metric since it doesn&#039;t always fulfill the positivity and symmetry requirements in a digraph.&lt;br /&gt;
&lt;br /&gt;
== Routing, Forwarding and Flooding ==&lt;br /&gt;
&lt;br /&gt;
With routing we typically mean the process of selecting a path for traffic in a network. In computer science literature, there are two main groups of approaches to routing.&lt;br /&gt;
&lt;br /&gt;
On the one hand there are the &#039;&#039;&#039;hierarchical routing&#039;&#039;&#039; solutions. This is the approach taken in IP networks, where a set of subnetworks is defined using &#039;&#039;&#039;prefixes&#039;&#039;&#039; or &#039;&#039;&#039;subnet masks&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan.&amp;lt;/ref&amp;gt; A scalability issue with IP stems from not following the partial ordering implied by the subnetting in the delegation of IP addresses, causing fragmentation of the IP address space and making prefix aggregration in routers increasingly inefficient.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Rekhter&#039;s Law: Addressing can follow topology or topology can follow addressing. Choose one. RFC 4984.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the other hand we have &#039;&#039;&#039;geographic&#039;&#039;&#039; or &#039;&#039;&#039;geometric&#039;&#039;&#039; routing,&amp;lt;ref&amp;gt;Kuhn, F., Wattenhofer, R., and Zollinger, A. (2003). Worst-case optimal and average-case efficient geometric ad-hoc routing.&amp;lt;/ref&amp;gt; where each node is assigned a coordinate so next hops can be calculated making use of the coordinates of the direct neighbors.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Geographic coordinates are a compound name, consisting of latitudes and longitudes, but there is no order implied between these two coordinate spaces. Hence the partial ordering in our definition of an address.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The examples above illustrate that the concept of routing encompasses both the dissemination and gathering of information about the network, and the algorithms for calculation and selection of the paths. We will now define the concepts underpinning &amp;quot;routing&amp;quot; more formally. The reasoning behind it is similar to the reasoning commonly used in formulating (integer) linear programming solutions to problems in graph theory.&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; be a network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination vertices &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;, so that the following 4 conditions are met:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a directed acyclic subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only incoming arcs; and&lt;br /&gt;
# &amp;lt;math&amp;gt;A&#039; = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalently,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt; Proof of Equivalence: choose for &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; the length of the longest path between the corresponding vertices in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;. This also proves it covers &#039;&#039;all&#039;&#039; algorithms, unless you find a path longer than the longest path...&amp;lt;/ref&amp;gt; &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(u, v_d) &amp;lt; d(v, v_d)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;\cup_{v \in V} H(v) = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, either the distance function bounds the routing solution, or the routing solution bounds the distance function.&lt;br /&gt;
&lt;br /&gt;
The formal definition says that a routing algorithm is equivalent a tree-like structure where every node along any valid path selects one or more neighbors that are strictly &amp;quot;closer&amp;quot; to the destination than itself. This structure can contain multiple paths from source to destination, allowing routing solution that move different packets (or fragments) along different routes through the network. The key guarantee is that all these paths always make progress toward their destination and can not contain (permanent) loops - think of it like water flowing downhill where it may split into multiple streams, but each stream always flows to a lower elevation and can never flow back uphill.&lt;br /&gt;
&lt;br /&gt;
This definition is very broad &amp;quot;one or more neighbors&amp;quot; selection allows solutions that send duplicates, erasure coding packet fragments etc.&lt;br /&gt;
&lt;br /&gt;
We define &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; as any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns the set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;. &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; is often implemented as &#039;&#039;&#039;ROUTING&#039;&#039;&#039; with an additional edge selection step.&lt;br /&gt;
&lt;br /&gt;
The necessary and sufficient condition for &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is full knowledge of the graph &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; and a valid geodesic distance &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. For a given vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, the necessary and sufficient set of information to obtain &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt; is knowledge of its neighbor set &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; and the subset of the geodesic distances originating at its neighbors, &amp;lt;math&amp;gt;d_{v} \subset d: N(v) \times V \to \mathbb{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In less formal terms, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; provide a set of vertices and arcs, respectively, so that there are never loops if one travels to a next vertex or along an arc in the set. If implemented in a centralized way, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; roughly need to know the full network. When implemented in a distributed way, a node roughly needs to know its neighbors and the distances to the destination from itself and from all its neighbors.&lt;br /&gt;
&lt;br /&gt;
The definitions above show what information needs to be disseminated in a network to allow &#039;&#039;&#039;FORWARDING&#039;&#039;&#039;. Let&#039;s assume that vertices know their neighbors or incident outgoing arcs, then what is needed is a dissemination procedure for the (geodesic) distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. This is implemented in a class of dissemination protocols, called &#039;&#039;&#039;link-state routing protocols&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors (with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;) so that:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a connected subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs.&lt;br /&gt;
&lt;br /&gt;
Equivalently, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(v_s, u) &amp;gt; d(v_s, v)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; creates a connected tree rooted at &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; that reaches all (reachable) vertices in the network. Each vertex selects neighbors that are strictly farther from the source than itself, ensuring the flood propagates outward without backtracking.&lt;br /&gt;
&lt;br /&gt;
== Flow ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;flow&#039;&#039;&#039; is the abstraction of a collection of resources within a network layer that allow bidirectional communications using packets between two processes that are clients of this layer. A flow enables a point-to-point &#039;&#039;&#039;packet delivery service&#039;&#039;&#039; and can be viewed as a bidirectional pipe that has a number of observable quantities associated with it that describe the probability &amp;lt;math&amp;gt;p(S,t, \ldots) \in [0, 1]&amp;lt;/math&amp;gt; of a packet of given size &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; being transferred within a certain period of time &amp;lt;math&amp;gt;[t_x, t_x + t]&amp;lt;/math&amp;gt;. The maximum probability for error-free transfer depends on the &#039;&#039;&#039;packet-drop-rate&#039;&#039;&#039; (PDR) and &#039;&#039;&#039;bit-error-rate&#039;&#039;&#039; (BER) of the flow.&lt;br /&gt;
&lt;br /&gt;
The Ouroboros architecture ensures that flows are &#039;&#039;&#039;content neutral&#039;&#039;&#039;, i.e. the probability &amp;lt;math&amp;gt;p(S, t, \ldots)&amp;lt;/math&amp;gt; above is independent of the bits that make up the packets sent along a flow.&lt;br /&gt;
&lt;br /&gt;
=== Flow Characteristics ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;delay&#039;&#039;&#039; or &#039;&#039;&#039;latency&#039;&#039;&#039; describes how long packets take to traverse the flow, and the variation on the delay is called &#039;&#039;&#039;jitter&#039;&#039;&#039;, or more precisely, &#039;&#039;&#039;packet delay variation&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 3393: IP Packet Delay Variation Metric for IP Performance Metrics (IPPM).&amp;lt;/ref&amp;gt; The delay for a flow has four main components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Propagation&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Queuing&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Transmission&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Processing&#039;&#039;&#039; delay&lt;br /&gt;
&lt;br /&gt;
=== Flow Bounds ===&lt;br /&gt;
&lt;br /&gt;
There are 2 upper bounds:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Lifetime&#039;&#039;&#039; (MPL) is the maximum amount of time that a packet can take to transfer over the flow&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Size&#039;&#039;&#039; (MPS) is the maximum length for a packet to be acceptable for transfer&lt;br /&gt;
&lt;br /&gt;
In other words, the probability for a packet to arrive after MPL expires should be close to 0,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;This may be hard to guarantee with 100 percent certainty, so MPL should be large enough so that this probability is 0 in practice. Ouroboros estimates MPL based on the Layer characteristics. IP has a bound on the Maximum Datagram Lifetime (MDL) via the Time-To-Live (v4) or Hop Limit (v6) decrement in each router to a maximum of 255 seconds (RFC 791), with a recommended value of 64 seconds (RFC 1700). In addition, TCP defines the Maximum Segment Lifetime (MSL) as 120s (RFC 793).&amp;lt;/ref&amp;gt; and the probability for a packet to arrive that exceeds the MPS is equal to 0.&lt;br /&gt;
&lt;br /&gt;
Similarly, there can be lower bounds such as Minimum Packet Lifetime (mPL) and Minimum Packet Size (mPS).&lt;br /&gt;
&lt;br /&gt;
=== Flow Resources ===&lt;br /&gt;
&lt;br /&gt;
The resources that make up a layer are finite, limiting the total number of packets that can traverse the network layer in a given period of time. Flows provide the mechanism to put a network layer fully in control of its own resources. The resources that constitute the flow can either be shared with other flows or dedicated (reserved) for this particular flow.&lt;br /&gt;
&lt;br /&gt;
Other externally measureable quantities can be associated with a flow, such as bandwidth and load for flows with reserved resources. The probability function may depend on these quantities (e.g. if the load reaches a certain threshold, delay could increase).&lt;br /&gt;
&lt;br /&gt;
=== Flow Identifiers ===&lt;br /&gt;
&lt;br /&gt;
A flow endpoint is identified in a system by a &#039;&#039;&#039;flow ID&#039;&#039;&#039; (FID), which defines the &#039;&#039;&#039;layer boundary&#039;&#039;&#039;&amp;lt;ref&amp;gt;In this respect, a flow id is similar to an OSI &#039;&#039;&#039;Service Access Point&#039;&#039;&#039; (SAP) or RINA &#039;&#039;&#039;port id&#039;&#039;&#039;.&amp;lt;/ref&amp;gt;. For security reasons, a process has no direct access to the flow, but rather accesses the flow through a &#039;&#039;&#039;Flow Descriptor&#039;&#039;&#039; (FD) to read and write from a flow. Flow identifiers are unique within the scope of a system, flow descriptors are unique within the scope of a process&amp;lt;ref&amp;gt;This is similar in function to a UNIX file descriptor. A UNIX kernel space implementation of Ouroboros would probably use file descriptors for flow descriptors.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Flows are an important concept for enabling Quality-of-Service (QoS) in a layer.&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references group=&amp;quot;note&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1874</id>
		<title>Definitions</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1874"/>
		<updated>2026-01-04T11:30:04Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Routing, Forwarding and Flooding */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Definitions: Flow, Routing, and Forwarding =&lt;br /&gt;
&lt;br /&gt;
This document contains formal definitions used in the Ouroboros architecture. The graph definitions follow Dieter Jungnickel&#039;s excellent &#039;&#039;Graph, Networks and Algorithms&#039;&#039;&amp;lt;ref&amp;gt;Jungnickel, D. (2007). Graphs, Networks and Algorithms.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Basic Graph Definitions ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;graph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, E)&amp;lt;/math&amp;gt; consisting of a set of &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; and a set of &#039;&#039;&#039;edges&#039;&#039;&#039; &amp;lt;math&amp;gt;E \subset V^2&amp;lt;/math&amp;gt; of two-element subsets of &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt;. An edge &amp;lt;math&amp;gt;e = (v_i,v_j)&amp;lt;/math&amp;gt; has (distinct) end vertices &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed graph&#039;&#039;&#039; or &#039;&#039;&#039;digraph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; consisting of a set &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; of vertices and a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of ordered pairs &amp;lt;math&amp;gt;(v_i, v_j)&amp;lt;/math&amp;gt; (called &#039;&#039;&#039;arcs&#039;&#039;&#039;) where &amp;lt;math&amp;gt;v_i \neq v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;network&#039;&#039;&#039; is a digraph &amp;lt;math&amp;gt;G = (V,A)&amp;lt;/math&amp;gt; on which a mapping &amp;lt;math&amp;gt;w: A \to \mathbb{R}&amp;lt;/math&amp;gt; from the edgeset to the reals is defined; the number &amp;lt;math&amp;gt;w(a)&amp;lt;/math&amp;gt; is called the &#039;&#039;&#039;weight&#039;&#039;&#039; of the arc &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;The weight of an edge is often called a &#039;&#039;metric&#039;&#039; in computer science literature (e.g. BGP metric). To avoid confusion, we use the term &#039;&#039;metric&#039;&#039; only in its mathematical meaning.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;a = (v_i,v_j) \in A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; is &#039;&#039;&#039;adjacent&#039;&#039;&#039; to &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt; and &#039;&#039;&#039;incident&#039;&#039;&#039; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. The set of &#039;&#039;&#039;neighbors&#039;&#039;&#039; &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; of a vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is the set of vertices that are adjacent to &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, where &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; contains all &amp;lt;math&amp;gt;u \in V&amp;lt;/math&amp;gt; such that &amp;lt;math&amp;gt;(v, u) \in A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Walks, Paths, and Cycles ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;walk&#039;&#039;&#039; is a sequence of vertices &amp;lt;math&amp;gt;\mathcal{W} = (v_0, v_1, \dots , v_n)&amp;lt;/math&amp;gt; so that &amp;lt;math&amp;gt;a_i = (v_{i-1},v_i) \in A , i = 1, \dots, n&amp;lt;/math&amp;gt;. So each walk also implies a sequence of edges. We define the weight of a walk &amp;lt;math&amp;gt;\mathcal{W}&amp;lt;/math&amp;gt; as the sum of the weights of its arcs, &amp;lt;math&amp;gt;w(\mathcal{W}) = \sum_{i=1}^n w(a_i)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;source&#039;&#039;&#039; &amp;lt;math&amp;gt;v_0&amp;lt;/math&amp;gt; and &#039;&#039;&#039;destination&#039;&#039;&#039; &amp;lt;math&amp;gt;v_n&amp;lt;/math&amp;gt; are the same (&amp;lt;math&amp;gt;v_0 = v_n&amp;lt;/math&amp;gt;), the walk is &#039;&#039;&#039;closed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A walk where each of the arcs &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; is distinct is called a &#039;&#039;&#039;trail&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;path&#039;&#039;&#039; is a trail for which each of the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;closed trail&#039;&#039;&#039; for which the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct is called a &#039;&#039;&#039;cycle&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;A &#039;&#039;Hamiltonian cycle&#039;&#039; is a special case of a closed walk that includes every vertex in the graph exactly once. This is necessarily also a closed trail.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed acyclic graph&#039;&#039;&#039; (DAG) is a digraph that does not contain any cycles.&lt;br /&gt;
&lt;br /&gt;
If for every pair of vertices &amp;lt;math&amp;gt;v_s, v_d \in V&amp;lt;/math&amp;gt; there is at least one path &amp;lt;math&amp;gt;\mathcal{P} = (v_s, \dots, v_d)&amp;lt;/math&amp;gt;, we call the (di)graph &#039;&#039;&#039;connected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Distance and Metrics ===&lt;br /&gt;
&lt;br /&gt;
The distance function defined by the weight of the shortest path between two vertices in a network (or &amp;lt;math&amp;gt;\infty&amp;lt;/math&amp;gt; if no such path exists) is called the &#039;&#039;geodesic&#039;&#039; distance.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metric&#039;&#039;&#039; is a (distance) function &amp;lt;math&amp;gt;d: X^2 \to [0, +\infty)&amp;lt;/math&amp;gt; fulfilling positivity, symmetry and triangle inequality:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x,y,z \in X: d(x, y) \geq 0 \land d(x,y) = d(y,x) \land d(x,z) \leq d(x,y) + d(y,z)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A geodesic distance is in general not a metric since it doesn&#039;t always fulfill the positivity and symmetry requirements in a digraph.&lt;br /&gt;
&lt;br /&gt;
== Routing, Forwarding and Flooding ==&lt;br /&gt;
&lt;br /&gt;
With routing we typically mean the process of selecting a path for traffic in a network. In computer science literature, there are two main groups of approaches to routing.&lt;br /&gt;
&lt;br /&gt;
On the one hand there are the &#039;&#039;&#039;hierarchical routing&#039;&#039;&#039; solutions. This is the approach taken in IP networks, where a set of subnetworks is defined using &#039;&#039;&#039;prefixes&#039;&#039;&#039; or &#039;&#039;&#039;subnet masks&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan.&amp;lt;/ref&amp;gt; A scalability issue with IP stems from not following the partial ordering implied by the subnetting in the delegation of IP addresses, causing fragmentation of the IP address space and making prefix aggregration in routers increasingly inefficient.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Rekhter&#039;s Law: Addressing can follow topology or topology can follow addressing. Choose one. RFC 4984.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the other hand we have &#039;&#039;&#039;geographic&#039;&#039;&#039; or &#039;&#039;&#039;geometric&#039;&#039;&#039; routing,&amp;lt;ref&amp;gt;Kuhn, F., Wattenhofer, R., and Zollinger, A. (2003). Worst-case optimal and average-case efficient geometric ad-hoc routing.&amp;lt;/ref&amp;gt; where each node is assigned a coordinate so next hops can be calculated making use of the coordinates of the direct neighbors.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Geographic coordinates are a compound name, consisting of latitudes and longitudes, but there is no order implied between these two coordinate spaces. Hence the partial ordering in our definition of an address.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The examples above illustrate that the concept of routing encompasses both the dissemination and gathering of information about the network, and the algorithms for calculation and selection of the paths. We will now define the concepts underpinning &amp;quot;routing&amp;quot; more formally. The reasoning behind it is similar to the reasoning commonly used in formulating (integer) linear programming solutions to problems in graph theory.&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; be a network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination vertices &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;, so that the following 4 conditions are met:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a directed acyclic subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only incoming arcs; and&lt;br /&gt;
# &amp;lt;math&amp;gt;A&#039; = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalently,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt; Proof of Equivalence: choose for &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; the length of the longest path between the corresponding vertices in &amp;lt;math&amp;gt;D.&amp;lt;/math&amp;gt;. This also proves it covers &#039;&#039;all&#039;&#039; algorithms, unless you find a path longer than the longest path...&amp;lt;/ref&amp;gt; &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(u, v_d) &amp;lt; d(v, v_d)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;\cup_{v \in V} H(v) = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, either the distance function bounds the routing solution, or the routing solution bounds the distance function.&lt;br /&gt;
&lt;br /&gt;
The formal definition says that a routing algorithm is equivalent a tree-like structure where every node along any valid path selects one or more neighbors that are strictly &amp;quot;closer&amp;quot; to the destination than itself. This structure can contain multiple paths from source to destination, allowing routing solution that move different packets (or fragments) along different routes through the network. The key guarantee is that all these paths always make progress toward their destination and can not contain (permanent) loops - think of it like water flowing downhill where it may split into multiple streams, but each stream always flows to a lower elevation and can never flow back uphill.&lt;br /&gt;
&lt;br /&gt;
This definition is very broad &amp;quot;one or more neighbors&amp;quot; selection allows solutions that send duplicates, erasure coding packet fragments etc.&lt;br /&gt;
&lt;br /&gt;
We define &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; as any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns the set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;. &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; is often implemented as &#039;&#039;&#039;ROUTING&#039;&#039;&#039; with an additional edge selection step.&lt;br /&gt;
&lt;br /&gt;
The necessary and sufficient condition for &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is full knowledge of the graph &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; and a valid geodesic distance &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. For a given vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, the necessary and sufficient set of information to obtain &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt; is knowledge of its neighbor set &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; and the subset of the geodesic distances originating at its neighbors, &amp;lt;math&amp;gt;d_{v} \subset d: N(v) \times V \to \mathbb{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In less formal terms, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; provide a set of vertices and arcs, respectively, so that there are never loops if one travels to a next vertex or along an arc in the set. If implemented in a centralized way, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; roughly need to know the full network. When implemented in a distributed way, a node roughly needs to know its neighbors and the distances to the destination from itself and from all its neighbors.&lt;br /&gt;
&lt;br /&gt;
The definitions above show what information needs to be disseminated in a network to allow &#039;&#039;&#039;FORWARDING&#039;&#039;&#039;. Let&#039;s assume that vertices know their neighbors or incident outgoing arcs, then what is needed is a dissemination procedure for the (geodesic) distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. This is implemented in a class of dissemination protocols, called &#039;&#039;&#039;link-state routing protocols&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors (with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;) so that:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a connected subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs.&lt;br /&gt;
&lt;br /&gt;
Equivalently, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(v_s, u) &amp;gt; d(v_s, v)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; creates a connected tree rooted at &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; that reaches all (reachable) vertices in the network. Each vertex selects neighbors that are strictly farther from the source than itself, ensuring the flood propagates outward without backtracking.&lt;br /&gt;
&lt;br /&gt;
== Flow ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;flow&#039;&#039;&#039; is the abstraction of a collection of resources within a network layer that allow bidirectional communications using packets between two processes that are clients of this layer. A flow enables a point-to-point &#039;&#039;&#039;packet delivery service&#039;&#039;&#039; and can be viewed as a bidirectional pipe that has a number of observable quantities associated with it that describe the probability &amp;lt;math&amp;gt;p(S,t, \ldots) \in [0, 1]&amp;lt;/math&amp;gt; of a packet of given size &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; being transferred within a certain period of time &amp;lt;math&amp;gt;[t_x, t_x + t]&amp;lt;/math&amp;gt;. The maximum probability for error-free transfer depends on the &#039;&#039;&#039;packet-drop-rate&#039;&#039;&#039; (PDR) and &#039;&#039;&#039;bit-error-rate&#039;&#039;&#039; (BER) of the flow.&lt;br /&gt;
&lt;br /&gt;
The Ouroboros architecture ensures that flows are &#039;&#039;&#039;content neutral&#039;&#039;&#039;, i.e. the probability &amp;lt;math&amp;gt;p(S, t, \ldots)&amp;lt;/math&amp;gt; above is independent of the bits that make up the packets sent along a flow.&lt;br /&gt;
&lt;br /&gt;
=== Flow Characteristics ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;delay&#039;&#039;&#039; or &#039;&#039;&#039;latency&#039;&#039;&#039; describes how long packets take to traverse the flow, and the variation on the delay is called &#039;&#039;&#039;jitter&#039;&#039;&#039;, or more precisely, &#039;&#039;&#039;packet delay variation&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 3393: IP Packet Delay Variation Metric for IP Performance Metrics (IPPM).&amp;lt;/ref&amp;gt; The delay for a flow has four main components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Propagation&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Queuing&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Transmission&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Processing&#039;&#039;&#039; delay&lt;br /&gt;
&lt;br /&gt;
=== Flow Bounds ===&lt;br /&gt;
&lt;br /&gt;
There are 2 upper bounds:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Lifetime&#039;&#039;&#039; (MPL) is the maximum amount of time that a packet can take to transfer over the flow&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Size&#039;&#039;&#039; (MPS) is the maximum length for a packet to be acceptable for transfer&lt;br /&gt;
&lt;br /&gt;
In other words, the probability for a packet to arrive after MPL expires should be close to 0,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;This may be hard to guarantee with 100 percent certainty, so MPL should be large enough so that this probability is 0 in practice. Ouroboros estimates MPL based on the Layer characteristics. IP has a bound on the Maximum Datagram Lifetime (MDL) via the Time-To-Live (v4) or Hop Limit (v6) decrement in each router to a maximum of 255 seconds (RFC 791), with a recommended value of 64 seconds (RFC 1700). In addition, TCP defines the Maximum Segment Lifetime (MSL) as 120s (RFC 793).&amp;lt;/ref&amp;gt; and the probability for a packet to arrive that exceeds the MPS is equal to 0.&lt;br /&gt;
&lt;br /&gt;
Similarly, there can be lower bounds such as Minimum Packet Lifetime (mPL) and Minimum Packet Size (mPS).&lt;br /&gt;
&lt;br /&gt;
=== Flow Resources ===&lt;br /&gt;
&lt;br /&gt;
The resources that make up a layer are finite, limiting the total number of packets that can traverse the network layer in a given period of time. Flows provide the mechanism to put a network layer fully in control of its own resources. The resources that constitute the flow can either be shared with other flows or dedicated (reserved) for this particular flow.&lt;br /&gt;
&lt;br /&gt;
Other externally measureable quantities can be associated with a flow, such as bandwidth and load for flows with reserved resources. The probability function may depend on these quantities (e.g. if the load reaches a certain threshold, delay could increase).&lt;br /&gt;
&lt;br /&gt;
=== Flow Identifiers ===&lt;br /&gt;
&lt;br /&gt;
A flow endpoint is identified in a system by a &#039;&#039;&#039;flow ID&#039;&#039;&#039; (FID), which defines the &#039;&#039;&#039;layer boundary&#039;&#039;&#039;&amp;lt;ref&amp;gt;In this respect, a flow id is similar to an OSI &#039;&#039;&#039;Service Access Point&#039;&#039;&#039; (SAP) or RINA &#039;&#039;&#039;port id&#039;&#039;&#039;.&amp;lt;/ref&amp;gt;. For security reasons, a process has no direct access to the flow, but rather accesses the flow through a &#039;&#039;&#039;Flow Descriptor&#039;&#039;&#039; (FD) to read and write from a flow. Flow identifiers are unique within the scope of a system, flow descriptors are unique within the scope of a process&amp;lt;ref&amp;gt;This is similar in function to a UNIX file descriptor. A UNIX kernel space implementation of Ouroboros would probably use file descriptors for flow descriptors.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Flows are an important concept for enabling Quality-of-Service (QoS) in a layer.&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references group=&amp;quot;note&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1873</id>
		<title>Definitions</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1873"/>
		<updated>2026-01-04T11:19:59Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Flow Bounds */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Definitions: Flow, Routing, and Forwarding =&lt;br /&gt;
&lt;br /&gt;
This document contains formal definitions used in the Ouroboros architecture. The graph definitions follow Dieter Jungnickel&#039;s excellent &#039;&#039;Graph, Networks and Algorithms&#039;&#039;&amp;lt;ref&amp;gt;Jungnickel, D. (2007). Graphs, Networks and Algorithms.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Basic Graph Definitions ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;graph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, E)&amp;lt;/math&amp;gt; consisting of a set of &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; and a set of &#039;&#039;&#039;edges&#039;&#039;&#039; &amp;lt;math&amp;gt;E \subset V^2&amp;lt;/math&amp;gt; of two-element subsets of &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt;. An edge &amp;lt;math&amp;gt;e = (v_i,v_j)&amp;lt;/math&amp;gt; has (distinct) end vertices &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed graph&#039;&#039;&#039; or &#039;&#039;&#039;digraph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; consisting of a set &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; of vertices and a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of ordered pairs &amp;lt;math&amp;gt;(v_i, v_j)&amp;lt;/math&amp;gt; (called &#039;&#039;&#039;arcs&#039;&#039;&#039;) where &amp;lt;math&amp;gt;v_i \neq v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;network&#039;&#039;&#039; is a digraph &amp;lt;math&amp;gt;G = (V,A)&amp;lt;/math&amp;gt; on which a mapping &amp;lt;math&amp;gt;w: A \to \mathbb{R}&amp;lt;/math&amp;gt; from the edgeset to the reals is defined; the number &amp;lt;math&amp;gt;w(a)&amp;lt;/math&amp;gt; is called the &#039;&#039;&#039;weight&#039;&#039;&#039; of the arc &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;The weight of an edge is often called a &#039;&#039;metric&#039;&#039; in computer science literature (e.g. BGP metric). To avoid confusion, we use the term &#039;&#039;metric&#039;&#039; only in its mathematical meaning.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;a = (v_i,v_j) \in A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; is &#039;&#039;&#039;adjacent&#039;&#039;&#039; to &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt; and &#039;&#039;&#039;incident&#039;&#039;&#039; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. The set of &#039;&#039;&#039;neighbors&#039;&#039;&#039; &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; of a vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is the set of vertices that are adjacent to &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, where &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; contains all &amp;lt;math&amp;gt;u \in V&amp;lt;/math&amp;gt; such that &amp;lt;math&amp;gt;(v, u) \in A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Walks, Paths, and Cycles ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;walk&#039;&#039;&#039; is a sequence of vertices &amp;lt;math&amp;gt;\mathcal{W} = (v_0, v_1, \dots , v_n)&amp;lt;/math&amp;gt; so that &amp;lt;math&amp;gt;a_i = (v_{i-1},v_i) \in A , i = 1, \dots, n&amp;lt;/math&amp;gt;. So each walk also implies a sequence of edges. We define the weight of a walk &amp;lt;math&amp;gt;\mathcal{W}&amp;lt;/math&amp;gt; as the sum of the weights of its arcs, &amp;lt;math&amp;gt;w(\mathcal{W}) = \sum_{i=1}^n w(a_i)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;source&#039;&#039;&#039; &amp;lt;math&amp;gt;v_0&amp;lt;/math&amp;gt; and &#039;&#039;&#039;destination&#039;&#039;&#039; &amp;lt;math&amp;gt;v_n&amp;lt;/math&amp;gt; are the same (&amp;lt;math&amp;gt;v_0 = v_n&amp;lt;/math&amp;gt;), the walk is &#039;&#039;&#039;closed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A walk where each of the arcs &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; is distinct is called a &#039;&#039;&#039;trail&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;path&#039;&#039;&#039; is a trail for which each of the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;closed trail&#039;&#039;&#039; for which the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct is called a &#039;&#039;&#039;cycle&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;A &#039;&#039;Hamiltonian cycle&#039;&#039; is a special case of a closed walk that includes every vertex in the graph exactly once. This is necessarily also a closed trail.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed acyclic graph&#039;&#039;&#039; (DAG) is a digraph that does not contain any cycles.&lt;br /&gt;
&lt;br /&gt;
If for every pair of vertices &amp;lt;math&amp;gt;v_s, v_d \in V&amp;lt;/math&amp;gt; there is at least one path &amp;lt;math&amp;gt;\mathcal{P} = (v_s, \dots, v_d)&amp;lt;/math&amp;gt;, we call the (di)graph &#039;&#039;&#039;connected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Distance and Metrics ===&lt;br /&gt;
&lt;br /&gt;
The distance function defined by the weight of the shortest path between two vertices in a network (or &amp;lt;math&amp;gt;\infty&amp;lt;/math&amp;gt; if no such path exists) is called the &#039;&#039;geodesic&#039;&#039; distance.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metric&#039;&#039;&#039; is a (distance) function &amp;lt;math&amp;gt;d: X^2 \to [0, +\infty)&amp;lt;/math&amp;gt; fulfilling positivity, symmetry and triangle inequality:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x,y,z \in X: d(x, y) \geq 0 \land d(x,y) = d(y,x) \land d(x,z) \leq d(x,y) + d(y,z)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A geodesic distance is in general not a metric since it doesn&#039;t always fulfill the positivity and symmetry requirements in a digraph.&lt;br /&gt;
&lt;br /&gt;
== Routing, Forwarding and Flooding ==&lt;br /&gt;
&lt;br /&gt;
With routing we typically mean the process of selecting a path for traffic in a network. In computer science literature, there are two main groups of approaches to routing.&lt;br /&gt;
&lt;br /&gt;
On the one hand there are the &#039;&#039;&#039;hierarchical routing&#039;&#039;&#039; solutions. This is the approach taken in IP networks, where a set of subnetworks is defined using &#039;&#039;&#039;prefixes&#039;&#039;&#039; or &#039;&#039;&#039;subnet masks&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan.&amp;lt;/ref&amp;gt; A scalability issue with IP stems from not following the partial ordering implied by the subnetting in the delegation of IP addresses, causing fragmentation of the IP address space and making prefix aggregration in routers increasingly inefficient.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Rekhter&#039;s Law: Addressing can follow topology or topology can follow addressing. Choose one. RFC 4984.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the other hand we have &#039;&#039;&#039;geographic&#039;&#039;&#039; or &#039;&#039;&#039;geometric&#039;&#039;&#039; routing,&amp;lt;ref&amp;gt;Kuhn, F., Wattenhofer, R., and Zollinger, A. (2003). Worst-case optimal and average-case efficient geometric ad-hoc routing.&amp;lt;/ref&amp;gt; where each node is assigned a coordinate so next hops can be calculated making use of the coordinates of the direct neighbors.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Geographic coordinates are a compound name, consisting of latitudes and longitudes, but there is no order implied between these two coordinate spaces. Hence the partial ordering in our definition of an address.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The examples above illustrate that the concept of routing encompasses both the dissemination and gathering of information about the network, and the algorithms for calculation and selection of the paths. We will now define the concepts underpinning &amp;quot;routing&amp;quot; more formally. The reasoning behind it is similar to the reasoning commonly used in formulating (integer) linear programming solutions to problems in graph theory.&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; be a network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination vertices &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;, so that the following 4 conditions are met:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a directed acyclic subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only incoming arcs; and&lt;br /&gt;
# &amp;lt;math&amp;gt;A&#039; = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalently,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt; Proof of Equivalence: choose for &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; the length of the longest path between the corresponding vertices in &amp;lt;math&amp;gt;D.&amp;lt;/math&amp;gt;.&amp;lt;/ref&amp;gt; &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(u, v_d) &amp;lt; d(v, v_d)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;\cup_{v \in V} H(v) = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, either the distance function bounds the routing solution, or the routing solution bounds the distance function.&lt;br /&gt;
&lt;br /&gt;
The formal definition says that a routing algorithm is equivalent a tree-like structure where every node along any valid path selects one or more neighbors that are strictly &amp;quot;closer&amp;quot; to the destination than itself. This structure can contain multiple paths from source to destination, allowing routing solution that move different packets (or fragments) along different routes through the network. The key guarantee is that all these paths always make progress toward their destination and can not contain (permanent) loops - think of it like water flowing downhill where it may split into multiple streams, but each stream always flows to a lower elevation and can never flow back uphill.&lt;br /&gt;
&lt;br /&gt;
This definition is very broad &amp;quot;one or more neighbors&amp;quot; selection allows solutions that send duplicates, erasure coding packet fragments etc.&lt;br /&gt;
&lt;br /&gt;
We define &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; as any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns the set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;. &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; is often implemented as &#039;&#039;&#039;ROUTING&#039;&#039;&#039; with an additional edge selection step.&lt;br /&gt;
&lt;br /&gt;
The necessary and sufficient condition for &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is full knowledge of the graph &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; and a valid geodesic distance &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. For a given vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, the necessary and sufficient set of information to obtain &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt; is knowledge of its neighbor set &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; and the subset of the geodesic distances originating at its neighbors, &amp;lt;math&amp;gt;d_{v} \subset d: N(v) \times V \to \mathbb{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In less formal terms, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; provide a set of vertices and arcs, respectively, so that there are never loops if one travels to a next vertex or along an arc in the set. If implemented in a centralized way, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; roughly need to know the full network. When implemented in a distributed way, a node roughly needs to know its neighbors and the distances to the destination from itself and from all its neighbors.&lt;br /&gt;
&lt;br /&gt;
The definitions above show what information needs to be disseminated in a network to allow &#039;&#039;&#039;FORWARDING&#039;&#039;&#039;. Let&#039;s assume that vertices know their neighbors or incident outgoing arcs, then what is needed is a dissemination procedure for the (geodesic) distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. This is implemented in a class of dissemination protocols, called &#039;&#039;&#039;link-state routing protocols&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors (with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;) so that:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a connected subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs.&lt;br /&gt;
&lt;br /&gt;
Equivalently, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(v_s, u) &amp;gt; d(v_s, v)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; creates a connected tree rooted at &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; that reaches all (reachable) vertices in the network. Each vertex selects neighbors that are strictly farther from the source than itself, ensuring the flood propagates outward without backtracking.&lt;br /&gt;
&lt;br /&gt;
== Flow ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;flow&#039;&#039;&#039; is the abstraction of a collection of resources within a network layer that allow bidirectional communications using packets between two processes that are clients of this layer. A flow enables a point-to-point &#039;&#039;&#039;packet delivery service&#039;&#039;&#039; and can be viewed as a bidirectional pipe that has a number of observable quantities associated with it that describe the probability &amp;lt;math&amp;gt;p(S,t, \ldots) \in [0, 1]&amp;lt;/math&amp;gt; of a packet of given size &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; being transferred within a certain period of time &amp;lt;math&amp;gt;[t_x, t_x + t]&amp;lt;/math&amp;gt;. The maximum probability for error-free transfer depends on the &#039;&#039;&#039;packet-drop-rate&#039;&#039;&#039; (PDR) and &#039;&#039;&#039;bit-error-rate&#039;&#039;&#039; (BER) of the flow.&lt;br /&gt;
&lt;br /&gt;
The Ouroboros architecture ensures that flows are &#039;&#039;&#039;content neutral&#039;&#039;&#039;, i.e. the probability &amp;lt;math&amp;gt;p(S, t, \ldots)&amp;lt;/math&amp;gt; above is independent of the bits that make up the packets sent along a flow.&lt;br /&gt;
&lt;br /&gt;
=== Flow Characteristics ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;delay&#039;&#039;&#039; or &#039;&#039;&#039;latency&#039;&#039;&#039; describes how long packets take to traverse the flow, and the variation on the delay is called &#039;&#039;&#039;jitter&#039;&#039;&#039;, or more precisely, &#039;&#039;&#039;packet delay variation&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 3393: IP Packet Delay Variation Metric for IP Performance Metrics (IPPM).&amp;lt;/ref&amp;gt; The delay for a flow has four main components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Propagation&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Queuing&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Transmission&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Processing&#039;&#039;&#039; delay&lt;br /&gt;
&lt;br /&gt;
=== Flow Bounds ===&lt;br /&gt;
&lt;br /&gt;
There are 2 upper bounds:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Lifetime&#039;&#039;&#039; (MPL) is the maximum amount of time that a packet can take to transfer over the flow&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Size&#039;&#039;&#039; (MPS) is the maximum length for a packet to be acceptable for transfer&lt;br /&gt;
&lt;br /&gt;
In other words, the probability for a packet to arrive after MPL expires should be close to 0,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;This may be hard to guarantee with 100 percent certainty, so MPL should be large enough so that this probability is 0 in practice. Ouroboros estimates MPL based on the Layer characteristics. IP has a bound on the Maximum Datagram Lifetime (MDL) via the Time-To-Live (v4) or Hop Limit (v6) decrement in each router to a maximum of 255 seconds (RFC 791), with a recommended value of 64 seconds (RFC 1700). In addition, TCP defines the Maximum Segment Lifetime (MSL) as 120s (RFC 793).&amp;lt;/ref&amp;gt; and the probability for a packet to arrive that exceeds the MPS is equal to 0.&lt;br /&gt;
&lt;br /&gt;
Similarly, there can be lower bounds such as Minimum Packet Lifetime (mPL) and Minimum Packet Size (mPS).&lt;br /&gt;
&lt;br /&gt;
=== Flow Resources ===&lt;br /&gt;
&lt;br /&gt;
The resources that make up a layer are finite, limiting the total number of packets that can traverse the network layer in a given period of time. Flows provide the mechanism to put a network layer fully in control of its own resources. The resources that constitute the flow can either be shared with other flows or dedicated (reserved) for this particular flow.&lt;br /&gt;
&lt;br /&gt;
Other externally measureable quantities can be associated with a flow, such as bandwidth and load for flows with reserved resources. The probability function may depend on these quantities (e.g. if the load reaches a certain threshold, delay could increase).&lt;br /&gt;
&lt;br /&gt;
=== Flow Identifiers ===&lt;br /&gt;
&lt;br /&gt;
A flow endpoint is identified in a system by a &#039;&#039;&#039;flow ID&#039;&#039;&#039; (FID), which defines the &#039;&#039;&#039;layer boundary&#039;&#039;&#039;&amp;lt;ref&amp;gt;In this respect, a flow id is similar to an OSI &#039;&#039;&#039;Service Access Point&#039;&#039;&#039; (SAP) or RINA &#039;&#039;&#039;port id&#039;&#039;&#039;.&amp;lt;/ref&amp;gt;. For security reasons, a process has no direct access to the flow, but rather accesses the flow through a &#039;&#039;&#039;Flow Descriptor&#039;&#039;&#039; (FD) to read and write from a flow. Flow identifiers are unique within the scope of a system, flow descriptors are unique within the scope of a process&amp;lt;ref&amp;gt;This is similar in function to a UNIX file descriptor. A UNIX kernel space implementation of Ouroboros would probably use file descriptors for flow descriptors.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Flows are an important concept for enabling Quality-of-Service (QoS) in a layer.&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references group=&amp;quot;note&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1872</id>
		<title>Definitions</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1872"/>
		<updated>2026-01-04T11:13:10Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Routing, Forwarding and Flooding */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Definitions: Flow, Routing, and Forwarding =&lt;br /&gt;
&lt;br /&gt;
This document contains formal definitions used in the Ouroboros architecture. The graph definitions follow Dieter Jungnickel&#039;s excellent &#039;&#039;Graph, Networks and Algorithms&#039;&#039;&amp;lt;ref&amp;gt;Jungnickel, D. (2007). Graphs, Networks and Algorithms.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Basic Graph Definitions ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;graph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, E)&amp;lt;/math&amp;gt; consisting of a set of &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; and a set of &#039;&#039;&#039;edges&#039;&#039;&#039; &amp;lt;math&amp;gt;E \subset V^2&amp;lt;/math&amp;gt; of two-element subsets of &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt;. An edge &amp;lt;math&amp;gt;e = (v_i,v_j)&amp;lt;/math&amp;gt; has (distinct) end vertices &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed graph&#039;&#039;&#039; or &#039;&#039;&#039;digraph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; consisting of a set &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; of vertices and a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of ordered pairs &amp;lt;math&amp;gt;(v_i, v_j)&amp;lt;/math&amp;gt; (called &#039;&#039;&#039;arcs&#039;&#039;&#039;) where &amp;lt;math&amp;gt;v_i \neq v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;network&#039;&#039;&#039; is a digraph &amp;lt;math&amp;gt;G = (V,A)&amp;lt;/math&amp;gt; on which a mapping &amp;lt;math&amp;gt;w: A \to \mathbb{R}&amp;lt;/math&amp;gt; from the edgeset to the reals is defined; the number &amp;lt;math&amp;gt;w(a)&amp;lt;/math&amp;gt; is called the &#039;&#039;&#039;weight&#039;&#039;&#039; of the arc &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;The weight of an edge is often called a &#039;&#039;metric&#039;&#039; in computer science literature (e.g. BGP metric). To avoid confusion, we use the term &#039;&#039;metric&#039;&#039; only in its mathematical meaning.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;a = (v_i,v_j) \in A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; is &#039;&#039;&#039;adjacent&#039;&#039;&#039; to &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt; and &#039;&#039;&#039;incident&#039;&#039;&#039; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. The set of &#039;&#039;&#039;neighbors&#039;&#039;&#039; &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; of a vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is the set of vertices that are adjacent to &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, where &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; contains all &amp;lt;math&amp;gt;u \in V&amp;lt;/math&amp;gt; such that &amp;lt;math&amp;gt;(v, u) \in A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Walks, Paths, and Cycles ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;walk&#039;&#039;&#039; is a sequence of vertices &amp;lt;math&amp;gt;\mathcal{W} = (v_0, v_1, \dots , v_n)&amp;lt;/math&amp;gt; so that &amp;lt;math&amp;gt;a_i = (v_{i-1},v_i) \in A , i = 1, \dots, n&amp;lt;/math&amp;gt;. So each walk also implies a sequence of edges. We define the weight of a walk &amp;lt;math&amp;gt;\mathcal{W}&amp;lt;/math&amp;gt; as the sum of the weights of its arcs, &amp;lt;math&amp;gt;w(\mathcal{W}) = \sum_{i=1}^n w(a_i)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;source&#039;&#039;&#039; &amp;lt;math&amp;gt;v_0&amp;lt;/math&amp;gt; and &#039;&#039;&#039;destination&#039;&#039;&#039; &amp;lt;math&amp;gt;v_n&amp;lt;/math&amp;gt; are the same (&amp;lt;math&amp;gt;v_0 = v_n&amp;lt;/math&amp;gt;), the walk is &#039;&#039;&#039;closed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A walk where each of the arcs &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; is distinct is called a &#039;&#039;&#039;trail&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;path&#039;&#039;&#039; is a trail for which each of the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;closed trail&#039;&#039;&#039; for which the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct is called a &#039;&#039;&#039;cycle&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;A &#039;&#039;Hamiltonian cycle&#039;&#039; is a special case of a closed walk that includes every vertex in the graph exactly once. This is necessarily also a closed trail.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed acyclic graph&#039;&#039;&#039; (DAG) is a digraph that does not contain any cycles.&lt;br /&gt;
&lt;br /&gt;
If for every pair of vertices &amp;lt;math&amp;gt;v_s, v_d \in V&amp;lt;/math&amp;gt; there is at least one path &amp;lt;math&amp;gt;\mathcal{P} = (v_s, \dots, v_d)&amp;lt;/math&amp;gt;, we call the (di)graph &#039;&#039;&#039;connected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Distance and Metrics ===&lt;br /&gt;
&lt;br /&gt;
The distance function defined by the weight of the shortest path between two vertices in a network (or &amp;lt;math&amp;gt;\infty&amp;lt;/math&amp;gt; if no such path exists) is called the &#039;&#039;geodesic&#039;&#039; distance.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metric&#039;&#039;&#039; is a (distance) function &amp;lt;math&amp;gt;d: X^2 \to [0, +\infty)&amp;lt;/math&amp;gt; fulfilling positivity, symmetry and triangle inequality:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x,y,z \in X: d(x, y) \geq 0 \land d(x,y) = d(y,x) \land d(x,z) \leq d(x,y) + d(y,z)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A geodesic distance is in general not a metric since it doesn&#039;t always fulfill the positivity and symmetry requirements in a digraph.&lt;br /&gt;
&lt;br /&gt;
== Routing, Forwarding and Flooding ==&lt;br /&gt;
&lt;br /&gt;
With routing we typically mean the process of selecting a path for traffic in a network. In computer science literature, there are two main groups of approaches to routing.&lt;br /&gt;
&lt;br /&gt;
On the one hand there are the &#039;&#039;&#039;hierarchical routing&#039;&#039;&#039; solutions. This is the approach taken in IP networks, where a set of subnetworks is defined using &#039;&#039;&#039;prefixes&#039;&#039;&#039; or &#039;&#039;&#039;subnet masks&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan.&amp;lt;/ref&amp;gt; A scalability issue with IP stems from not following the partial ordering implied by the subnetting in the delegation of IP addresses, causing fragmentation of the IP address space and making prefix aggregration in routers increasingly inefficient.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Rekhter&#039;s Law: Addressing can follow topology or topology can follow addressing. Choose one. RFC 4984.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the other hand we have &#039;&#039;&#039;geographic&#039;&#039;&#039; or &#039;&#039;&#039;geometric&#039;&#039;&#039; routing,&amp;lt;ref&amp;gt;Kuhn, F., Wattenhofer, R., and Zollinger, A. (2003). Worst-case optimal and average-case efficient geometric ad-hoc routing.&amp;lt;/ref&amp;gt; where each node is assigned a coordinate so next hops can be calculated making use of the coordinates of the direct neighbors.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Geographic coordinates are a compound name, consisting of latitudes and longitudes, but there is no order implied between these two coordinate spaces. Hence the partial ordering in our definition of an address.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The examples above illustrate that the concept of routing encompasses both the dissemination and gathering of information about the network, and the algorithms for calculation and selection of the paths. We will now define the concepts underpinning &amp;quot;routing&amp;quot; more formally. The reasoning behind it is similar to the reasoning commonly used in formulating (integer) linear programming solutions to problems in graph theory.&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; be a network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination vertices &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;, so that the following 4 conditions are met:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a directed acyclic subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only incoming arcs; and&lt;br /&gt;
# &amp;lt;math&amp;gt;A&#039; = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalently,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt; Proof of Equivalence: choose for &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; the length of the longest path between the corresponding vertices in &amp;lt;math&amp;gt;D.&amp;lt;/math&amp;gt;.&amp;lt;/ref&amp;gt; &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(u, v_d) &amp;lt; d(v, v_d)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;\cup_{v \in V} H(v) = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, either the distance function bounds the routing solution, or the routing solution bounds the distance function.&lt;br /&gt;
&lt;br /&gt;
The formal definition says that a routing algorithm is equivalent a tree-like structure where every node along any valid path selects one or more neighbors that are strictly &amp;quot;closer&amp;quot; to the destination than itself. This structure can contain multiple paths from source to destination, allowing routing solution that move different packets (or fragments) along different routes through the network. The key guarantee is that all these paths always make progress toward their destination and can not contain (permanent) loops - think of it like water flowing downhill where it may split into multiple streams, but each stream always flows to a lower elevation and can never flow back uphill.&lt;br /&gt;
&lt;br /&gt;
This definition is very broad &amp;quot;one or more neighbors&amp;quot; selection allows solutions that send duplicates, erasure coding packet fragments etc.&lt;br /&gt;
&lt;br /&gt;
We define &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; as any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns the set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;. &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; is often implemented as &#039;&#039;&#039;ROUTING&#039;&#039;&#039; with an additional edge selection step.&lt;br /&gt;
&lt;br /&gt;
The necessary and sufficient condition for &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is full knowledge of the graph &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; and a valid geodesic distance &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. For a given vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, the necessary and sufficient set of information to obtain &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt; is knowledge of its neighbor set &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; and the subset of the geodesic distances originating at its neighbors, &amp;lt;math&amp;gt;d_{v} \subset d: N(v) \times V \to \mathbb{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In less formal terms, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; provide a set of vertices and arcs, respectively, so that there are never loops if one travels to a next vertex or along an arc in the set. If implemented in a centralized way, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; roughly need to know the full network. When implemented in a distributed way, a node roughly needs to know its neighbors and the distances to the destination from itself and from all its neighbors.&lt;br /&gt;
&lt;br /&gt;
The definitions above show what information needs to be disseminated in a network to allow &#039;&#039;&#039;FORWARDING&#039;&#039;&#039;. Let&#039;s assume that vertices know their neighbors or incident outgoing arcs, then what is needed is a dissemination procedure for the (geodesic) distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. This is implemented in a class of dissemination protocols, called &#039;&#039;&#039;link-state routing protocols&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors (with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;) so that:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a connected subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs.&lt;br /&gt;
&lt;br /&gt;
Equivalently, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(v_s, u) &amp;gt; d(v_s, v)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; creates a connected tree rooted at &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; that reaches all (reachable) vertices in the network. Each vertex selects neighbors that are strictly farther from the source than itself, ensuring the flood propagates outward without backtracking.&lt;br /&gt;
&lt;br /&gt;
== Flow ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;flow&#039;&#039;&#039; is the abstraction of a collection of resources within a network layer that allow bidirectional communications using packets between two processes that are clients of this layer. A flow enables a point-to-point &#039;&#039;&#039;packet delivery service&#039;&#039;&#039; and can be viewed as a bidirectional pipe that has a number of observable quantities associated with it that describe the probability &amp;lt;math&amp;gt;p(S,t, \ldots) \in [0, 1]&amp;lt;/math&amp;gt; of a packet of given size &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; being transferred within a certain period of time &amp;lt;math&amp;gt;[t_x, t_x + t]&amp;lt;/math&amp;gt;. The maximum probability for error-free transfer depends on the &#039;&#039;&#039;packet-drop-rate&#039;&#039;&#039; (PDR) and &#039;&#039;&#039;bit-error-rate&#039;&#039;&#039; (BER) of the flow.&lt;br /&gt;
&lt;br /&gt;
The Ouroboros architecture ensures that flows are &#039;&#039;&#039;content neutral&#039;&#039;&#039;, i.e. the probability &amp;lt;math&amp;gt;p(S, t, \ldots)&amp;lt;/math&amp;gt; above is independent of the bits that make up the packets sent along a flow.&lt;br /&gt;
&lt;br /&gt;
=== Flow Characteristics ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;delay&#039;&#039;&#039; or &#039;&#039;&#039;latency&#039;&#039;&#039; describes how long packets take to traverse the flow, and the variation on the delay is called &#039;&#039;&#039;jitter&#039;&#039;&#039;, or more precisely, &#039;&#039;&#039;packet delay variation&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 3393: IP Packet Delay Variation Metric for IP Performance Metrics (IPPM).&amp;lt;/ref&amp;gt; The delay for a flow has four main components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Propagation&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Queuing&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Transmission&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Processing&#039;&#039;&#039; delay&lt;br /&gt;
&lt;br /&gt;
=== Flow Bounds ===&lt;br /&gt;
&lt;br /&gt;
There are 2 upper bounds:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Lifetime&#039;&#039;&#039; (MPL) is the maximum amount of time that a packet can take to transfer over the flow&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Size&#039;&#039;&#039; (MPS) is the maximum length for a packet to be acceptable for transfer&lt;br /&gt;
&lt;br /&gt;
In other words, the probability for a packet to arrive after MPL expires should be 0,&amp;lt;ref&amp;gt;This may be hard to guarantee with 100 percent certainty, so MPL should be large enough so that this probability is 0 in practice. IP has a bound on the Maximum Datagram Lifetime (MDL) via the Time-To-Live or Hop Limit decrement in each router to a maximum of 255 seconds (RFC 791), with a recommended value of 64 seconds (RFC 1700). In addition, TCP defines the Maximum Segment Lifetime (MSL) as 120s (RFC 793).&amp;lt;/ref&amp;gt; and the probability for a packet to arrive that exceeds the MPS is equal to 0.&lt;br /&gt;
&lt;br /&gt;
Similarly, there can be lower bounds such as Minimum Packet Lifetime (mPL) and Minimum Packet Size (mPS).&lt;br /&gt;
&lt;br /&gt;
=== Flow Resources ===&lt;br /&gt;
&lt;br /&gt;
The resources that make up a layer are finite, limiting the total number of packets that can traverse the network layer in a given period of time. Flows provide the mechanism to put a network layer fully in control of its own resources. The resources that constitute the flow can either be shared with other flows or dedicated (reserved) for this particular flow.&lt;br /&gt;
&lt;br /&gt;
Other externally measureable quantities can be associated with a flow, such as bandwidth and load for flows with reserved resources. The probability function may depend on these quantities (e.g. if the load reaches a certain threshold, delay could increase).&lt;br /&gt;
&lt;br /&gt;
=== Flow Identifiers ===&lt;br /&gt;
&lt;br /&gt;
A flow endpoint is identified in a system by a &#039;&#039;&#039;flow ID&#039;&#039;&#039; (FID), which defines the &#039;&#039;&#039;layer boundary&#039;&#039;&#039;&amp;lt;ref&amp;gt;In this respect, a flow id is similar to an OSI &#039;&#039;&#039;Service Access Point&#039;&#039;&#039; (SAP) or RINA &#039;&#039;&#039;port id&#039;&#039;&#039;.&amp;lt;/ref&amp;gt;. For security reasons, a process has no direct access to the flow, but rather accesses the flow through a &#039;&#039;&#039;Flow Descriptor&#039;&#039;&#039; (FD) to read and write from a flow. Flow identifiers are unique within the scope of a system, flow descriptors are unique within the scope of a process&amp;lt;ref&amp;gt;This is similar in function to a UNIX file descriptor. A UNIX kernel space implementation of Ouroboros would probably use file descriptors for flow descriptors.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Flows are an important concept for enabling Quality-of-Service (QoS) in a layer.&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references group=&amp;quot;note&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
	<entry>
		<id>https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1871</id>
		<title>Definitions</title>
		<link rel="alternate" type="text/html" href="https://ouroboros.rocks/mediawiki/index.php?title=Definitions&amp;diff=1871"/>
		<updated>2026-01-04T11:09:00Z</updated>

		<summary type="html">&lt;p&gt;Dimitri: /* Routing, Forwarding and Flooding */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Definitions: Flow, Routing, and Forwarding =&lt;br /&gt;
&lt;br /&gt;
This document contains formal definitions used in the Ouroboros architecture. The graph definitions follow Dieter Jungnickel&#039;s excellent &#039;&#039;Graph, Networks and Algorithms&#039;&#039;&amp;lt;ref&amp;gt;Jungnickel, D. (2007). Graphs, Networks and Algorithms.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Basic Graph Definitions ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;graph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, E)&amp;lt;/math&amp;gt; consisting of a set of &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; and a set of &#039;&#039;&#039;edges&#039;&#039;&#039; &amp;lt;math&amp;gt;E \subset V^2&amp;lt;/math&amp;gt; of two-element subsets of &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt;. An edge &amp;lt;math&amp;gt;e = (v_i,v_j)&amp;lt;/math&amp;gt; has (distinct) end vertices &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed graph&#039;&#039;&#039; or &#039;&#039;&#039;digraph&#039;&#039;&#039; is a pair &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; consisting of a set &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; of vertices and a set &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; of ordered pairs &amp;lt;math&amp;gt;(v_i, v_j)&amp;lt;/math&amp;gt; (called &#039;&#039;&#039;arcs&#039;&#039;&#039;) where &amp;lt;math&amp;gt;v_i \neq v_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;network&#039;&#039;&#039; is a digraph &amp;lt;math&amp;gt;G = (V,A)&amp;lt;/math&amp;gt; on which a mapping &amp;lt;math&amp;gt;w: A \to \mathbb{R}&amp;lt;/math&amp;gt; from the edgeset to the reals is defined; the number &amp;lt;math&amp;gt;w(a)&amp;lt;/math&amp;gt; is called the &#039;&#039;&#039;weight&#039;&#039;&#039; of the arc &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;The weight of an edge is often called a &#039;&#039;metric&#039;&#039; in computer science literature (e.g. BGP metric). To avoid confusion, we use the term &#039;&#039;metric&#039;&#039; only in its mathematical meaning.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;math&amp;gt;a = (v_i,v_j) \in A&amp;lt;/math&amp;gt;, then &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; is &#039;&#039;&#039;adjacent&#039;&#039;&#039; to &amp;lt;math&amp;gt;v_j&amp;lt;/math&amp;gt; and &#039;&#039;&#039;incident&#039;&#039;&#039; with &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt;. The set of &#039;&#039;&#039;neighbors&#039;&#039;&#039; &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; of a vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; is the set of vertices that are adjacent to &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, where &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; contains all &amp;lt;math&amp;gt;u \in V&amp;lt;/math&amp;gt; such that &amp;lt;math&amp;gt;(v, u) \in A&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Walks, Paths, and Cycles ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;walk&#039;&#039;&#039; is a sequence of vertices &amp;lt;math&amp;gt;\mathcal{W} = (v_0, v_1, \dots , v_n)&amp;lt;/math&amp;gt; so that &amp;lt;math&amp;gt;a_i = (v_{i-1},v_i) \in A , i = 1, \dots, n&amp;lt;/math&amp;gt;. So each walk also implies a sequence of edges. We define the weight of a walk &amp;lt;math&amp;gt;\mathcal{W}&amp;lt;/math&amp;gt; as the sum of the weights of its arcs, &amp;lt;math&amp;gt;w(\mathcal{W}) = \sum_{i=1}^n w(a_i)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;&#039;source&#039;&#039;&#039; &amp;lt;math&amp;gt;v_0&amp;lt;/math&amp;gt; and &#039;&#039;&#039;destination&#039;&#039;&#039; &amp;lt;math&amp;gt;v_n&amp;lt;/math&amp;gt; are the same (&amp;lt;math&amp;gt;v_0 = v_n&amp;lt;/math&amp;gt;), the walk is &#039;&#039;&#039;closed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A walk where each of the arcs &amp;lt;math&amp;gt;a_i&amp;lt;/math&amp;gt; is distinct is called a &#039;&#039;&#039;trail&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;path&#039;&#039;&#039; is a trail for which each of the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;closed trail&#039;&#039;&#039; for which the &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; are distinct is called a &#039;&#039;&#039;cycle&#039;&#039;&#039;&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;A &#039;&#039;Hamiltonian cycle&#039;&#039; is a special case of a closed walk that includes every vertex in the graph exactly once. This is necessarily also a closed trail.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;directed acyclic graph&#039;&#039;&#039; (DAG) is a digraph that does not contain any cycles.&lt;br /&gt;
&lt;br /&gt;
If for every pair of vertices &amp;lt;math&amp;gt;v_s, v_d \in V&amp;lt;/math&amp;gt; there is at least one path &amp;lt;math&amp;gt;\mathcal{P} = (v_s, \dots, v_d)&amp;lt;/math&amp;gt;, we call the (di)graph &#039;&#039;&#039;connected&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Distance and Metrics ===&lt;br /&gt;
&lt;br /&gt;
The distance function defined by the weight of the shortest path between two vertices in a network (or &amp;lt;math&amp;gt;\infty&amp;lt;/math&amp;gt; if no such path exists) is called the &#039;&#039;geodesic&#039;&#039; distance.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;metric&#039;&#039;&#039; is a (distance) function &amp;lt;math&amp;gt;d: X^2 \to [0, +\infty)&amp;lt;/math&amp;gt; fulfilling positivity, symmetry and triangle inequality:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\forall x,y,z \in X: d(x, y) \geq 0 \land d(x,y) = d(y,x) \land d(x,z) \leq d(x,y) + d(y,z)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A geodesic distance is in general not a metric since it doesn&#039;t always fulfill the positivity and symmetry requirements in a digraph.&lt;br /&gt;
&lt;br /&gt;
== Routing, Forwarding and Flooding ==&lt;br /&gt;
&lt;br /&gt;
With routing we typically mean the process of selecting a path for traffic in a network. In computer science literature, there are two main groups of approaches to routing.&lt;br /&gt;
&lt;br /&gt;
On the one hand there are the &#039;&#039;&#039;hierarchical routing&#039;&#039;&#039; solutions. This is the approach taken in IP networks, where a set of subnetworks is defined using &#039;&#039;&#039;prefixes&#039;&#039;&#039; or &#039;&#039;&#039;subnet masks&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 4632: Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan.&amp;lt;/ref&amp;gt; A scalability issue with IP stems from not following the partial ordering implied by the subnetting in the delegation of IP addresses, causing fragmentation of the IP address space and making prefix aggregration in routers increasingly inefficient.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Rekhter&#039;s Law: Addressing can follow topology or topology can follow addressing. Choose one. RFC 4984.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the other hand we have &#039;&#039;&#039;geographic&#039;&#039;&#039; or &#039;&#039;&#039;geometric&#039;&#039;&#039; routing,&amp;lt;ref&amp;gt;Kuhn, F., Wattenhofer, R., and Zollinger, A. (2003). Worst-case optimal and average-case efficient geometric ad-hoc routing.&amp;lt;/ref&amp;gt; where each node is assigned a coordinate so next hops can be calculated making use of the coordinates of the direct neighbors.&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt;Geographic coordinates are a compound name, consisting of latitudes and longitudes, but there is no order implied between these two coordinate spaces. Hence the partial ordering in our definition of an address.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The examples above illustrate that the concept of routing encompasses both the dissemination and gathering of information about the network, and the algorithms for calculation and selection of the paths. We will now define the concepts underpinning &amp;quot;routing&amp;quot; more formally. The reasoning behind it is similar to the reasoning commonly used in formulating (integer) linear programming solutions to problems in graph theory.&lt;br /&gt;
&lt;br /&gt;
Let &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; be a network.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination vertices &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;, so that the following 4 conditions are met:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a directed acyclic subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs;&lt;br /&gt;
# &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only incoming arcs; and&lt;br /&gt;
# &amp;lt;math&amp;gt;A&#039; = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalently,&amp;lt;ref group=&amp;quot;note&amp;quot;&amp;gt; Proof of Equivalence: choose for &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; the length of the longest path between the corresponding vertices in &amp;lt;math&amp;gt;D.&amp;lt;/math&amp;gt;.&amp;lt;/ref&amp;gt; &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is any algorithm that, given source and destination &#039;&#039;&#039;vertices&#039;&#039;&#039; &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt;, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(u, v_d) &amp;lt; d(v, v_d)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;\cup_{v \in V} H(v) = \emptyset&amp;lt;/math&amp;gt; if and only if there is no path &amp;lt;math&amp;gt;\mathcal{P}&amp;lt;/math&amp;gt; between &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;v_d&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, either the distance function bounds the routing solution, or the routing solution bounds the distance function.&lt;br /&gt;
&lt;br /&gt;
The formal definition says that a routing algorithm is equivalent a tree-like structure where every node along any valid path selects one or more neighbors that are strictly &amp;quot;closer&amp;quot; to the destination than itself. This structure can contain multiple paths from source to destination, allowing routing solution that move different packets (or fragments) along different routes through the network. The key guarantee is that all these paths always make progress toward their destination and can not contain (permanent) loops - think of it like water flowing downhill where it may split into multiple streams, but each stream always flows to a lower elevation and can never flow back uphill.&lt;br /&gt;
&lt;br /&gt;
This definition is very broad &amp;quot;one or more neighbors&amp;quot; selection allows solutions that send duplicates, erasure coding packet fragments etc.&lt;br /&gt;
&lt;br /&gt;
We define &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; as any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns the set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;. &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; is often implemented as &#039;&#039;&#039;ROUTING&#039;&#039;&#039; with an additional edge selection step.&lt;br /&gt;
&lt;br /&gt;
The necessary and sufficient condition for &#039;&#039;&#039;ROUTING&#039;&#039;&#039; is full knowledge of the graph &amp;lt;math&amp;gt;G = (V, A)&amp;lt;/math&amp;gt; and a valid geodesic distance &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. For a given vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, the necessary and sufficient set of information to obtain &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt; is knowledge of its neighbor set &amp;lt;math&amp;gt;N(v)&amp;lt;/math&amp;gt; and the subset of the geodesic distances originating at its neighbors, &amp;lt;math&amp;gt;d_{v} \subset d: N(v) \times V \to \mathbb{R}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In less formal terms, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; provide a set of vertices and arcs, respectively, so that there are never loops if one travels to a next vertex or along an arc in the set. If implemented in a centralized way, &#039;&#039;&#039;ROUTING&#039;&#039;&#039; and &#039;&#039;&#039;FORWARDING&#039;&#039;&#039; roughly need to know the full network. When implemented in a distributed way, a node roughly needs to know its neighbors and the distances to the destination from itself and from all its neighbors.&lt;br /&gt;
&lt;br /&gt;
The definitions above show what information needs to be disseminated in a network to allow &#039;&#039;&#039;FORWARDING&#039;&#039;&#039;. Let&#039;s assume that vertices know their neighbors or incident outgoing arcs, then what is needed is a dissemination procedure for the (geodesic) distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;. This is implemented in a class of dissemination protocols, called &#039;&#039;&#039;link-state routing protocols&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors (with the associated set of arcs &amp;lt;math&amp;gt;L(v)&amp;lt;/math&amp;gt;) so that:&lt;br /&gt;
&lt;br /&gt;
# The graph &amp;lt;math&amp;gt;D = (V&#039;, A&#039;) = (\cup_{v \in V}H(v), \cup_{v \in V}L(v))&amp;lt;/math&amp;gt; is a connected subgraph of &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;; and&lt;br /&gt;
# &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; is the only vertex in &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; with only outgoing arcs.&lt;br /&gt;
&lt;br /&gt;
Equivalently, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; is any algorithm that, for each vertex &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; in &amp;lt;math&amp;gt;V&amp;lt;/math&amp;gt; returns a subset &amp;lt;math&amp;gt;H(v) \subseteq N(v)&amp;lt;/math&amp;gt; of neighbors so that:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;math&amp;gt;\forall u \in H(v): d(v_s, u) &amp;gt; d(v_s, v)&amp;lt;/math&amp;gt; for any chosen distance function &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; on &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In other words, &#039;&#039;&#039;FLOODING&#039;&#039;&#039; creates a connected tree rooted at &amp;lt;math&amp;gt;v_s&amp;lt;/math&amp;gt; that reaches all vertices in the network. Each vertex selects neighbors that are strictly farther from the source than itself, ensuring the flood propagates outward without backtracking.&lt;br /&gt;
&lt;br /&gt;
== Flow ==&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;flow&#039;&#039;&#039; is the abstraction of a collection of resources within a network layer that allow bidirectional communications using packets between two processes that are clients of this layer. A flow enables a point-to-point &#039;&#039;&#039;packet delivery service&#039;&#039;&#039; and can be viewed as a bidirectional pipe that has a number of observable quantities associated with it that describe the probability &amp;lt;math&amp;gt;p(S,t, \ldots) \in [0, 1]&amp;lt;/math&amp;gt; of a packet of given size &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; being transferred within a certain period of time &amp;lt;math&amp;gt;[t_x, t_x + t]&amp;lt;/math&amp;gt;. The maximum probability for error-free transfer depends on the &#039;&#039;&#039;packet-drop-rate&#039;&#039;&#039; (PDR) and &#039;&#039;&#039;bit-error-rate&#039;&#039;&#039; (BER) of the flow.&lt;br /&gt;
&lt;br /&gt;
The Ouroboros architecture ensures that flows are &#039;&#039;&#039;content neutral&#039;&#039;&#039;, i.e. the probability &amp;lt;math&amp;gt;p(S, t, \ldots)&amp;lt;/math&amp;gt; above is independent of the bits that make up the packets sent along a flow.&lt;br /&gt;
&lt;br /&gt;
=== Flow Characteristics ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;delay&#039;&#039;&#039; or &#039;&#039;&#039;latency&#039;&#039;&#039; describes how long packets take to traverse the flow, and the variation on the delay is called &#039;&#039;&#039;jitter&#039;&#039;&#039;, or more precisely, &#039;&#039;&#039;packet delay variation&#039;&#039;&#039;.&amp;lt;ref&amp;gt;RFC 3393: IP Packet Delay Variation Metric for IP Performance Metrics (IPPM).&amp;lt;/ref&amp;gt; The delay for a flow has four main components:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Propagation&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Queuing&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Transmission&#039;&#039;&#039; delay&lt;br /&gt;
* &#039;&#039;&#039;Processing&#039;&#039;&#039; delay&lt;br /&gt;
&lt;br /&gt;
=== Flow Bounds ===&lt;br /&gt;
&lt;br /&gt;
There are 2 upper bounds:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Lifetime&#039;&#039;&#039; (MPL) is the maximum amount of time that a packet can take to transfer over the flow&lt;br /&gt;
* The &#039;&#039;&#039;Maximum Packet Size&#039;&#039;&#039; (MPS) is the maximum length for a packet to be acceptable for transfer&lt;br /&gt;
&lt;br /&gt;
In other words, the probability for a packet to arrive after MPL expires should be 0,&amp;lt;ref&amp;gt;This may be hard to guarantee with 100 percent certainty, so MPL should be large enough so that this probability is 0 in practice. IP has a bound on the Maximum Datagram Lifetime (MDL) via the Time-To-Live or Hop Limit decrement in each router to a maximum of 255 seconds (RFC 791), with a recommended value of 64 seconds (RFC 1700). In addition, TCP defines the Maximum Segment Lifetime (MSL) as 120s (RFC 793).&amp;lt;/ref&amp;gt; and the probability for a packet to arrive that exceeds the MPS is equal to 0.&lt;br /&gt;
&lt;br /&gt;
Similarly, there can be lower bounds such as Minimum Packet Lifetime (mPL) and Minimum Packet Size (mPS).&lt;br /&gt;
&lt;br /&gt;
=== Flow Resources ===&lt;br /&gt;
&lt;br /&gt;
The resources that make up a layer are finite, limiting the total number of packets that can traverse the network layer in a given period of time. Flows provide the mechanism to put a network layer fully in control of its own resources. The resources that constitute the flow can either be shared with other flows or dedicated (reserved) for this particular flow.&lt;br /&gt;
&lt;br /&gt;
Other externally measureable quantities can be associated with a flow, such as bandwidth and load for flows with reserved resources. The probability function may depend on these quantities (e.g. if the load reaches a certain threshold, delay could increase).&lt;br /&gt;
&lt;br /&gt;
=== Flow Identifiers ===&lt;br /&gt;
&lt;br /&gt;
A flow endpoint is identified in a system by a &#039;&#039;&#039;flow ID&#039;&#039;&#039; (FID), which defines the &#039;&#039;&#039;layer boundary&#039;&#039;&#039;&amp;lt;ref&amp;gt;In this respect, a flow id is similar to an OSI &#039;&#039;&#039;Service Access Point&#039;&#039;&#039; (SAP) or RINA &#039;&#039;&#039;port id&#039;&#039;&#039;.&amp;lt;/ref&amp;gt;. For security reasons, a process has no direct access to the flow, but rather accesses the flow through a &#039;&#039;&#039;Flow Descriptor&#039;&#039;&#039; (FD) to read and write from a flow. Flow identifiers are unique within the scope of a system, flow descriptors are unique within the scope of a process&amp;lt;ref&amp;gt;This is similar in function to a UNIX file descriptor. A UNIX kernel space implementation of Ouroboros would probably use file descriptors for flow descriptors.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Flows are an important concept for enabling Quality-of-Service (QoS) in a layer.&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references group=&amp;quot;note&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dimitri</name></author>
	</entry>
</feed>