Expert reference for the 5G NR Radio Link Control (RLC) protocol per 3GPP TS 38.322 v19.1.0. Use when the user asks about RLC modes (TM/UM/AM), PDU formats, state variables, timers, ARQ, segmentation, NTN/sidelink/MBS RLC, or implementing/debugging RLC entities.
Use this skill when the user asks about:
3GPP TS 38.322 v19.1.0 (Release 19) — Feb 2026 PDF: https://www.etsi.org/deliver/etsi_ts/138300_138399/138322/19.01.00_60/ts_138322v190100p.pdf Related specs: TS 38.321 (MAC), TS 38.323 (PDCP), TS 38.331 (RRC)
Three RLC entity types:
| Mode | Abbreviation | ARQ | Segmentation | Header | Logical Channels |
|---|---|---|---|---|---|
| Transparent Mode | TM | No | No | None | BCCH, CCCH, PCCH, SBCCH |
| Unacknowledged Mode | UM | No | Yes | SN+SI+SO | DTCH, SCCH, STCH, MCCH, MTCH |
| Acknowledged Mode | AM | Yes | Yes | SN+SI+SO+P+D/C | DCCH, DTCH, SCCH, STCH |
[ Data field (RLC SDU, no header) ]
No RLC header at all. SDU passed through unchanged.
[ R | R | SI(2b) | R | R | Data field ]
← 1 byte header →
[ R | R | SI(2b) | SN(6b) | Data field ]
← 1 byte header →
[ R | R | SI(2b) | R | R | R | R | R | SN(12b, split across 2nd byte) | (SO if SI≠00) | Data ]
←————— 2 byte header ——————→
SI field values:
00 = complete SDU (no SN field included)01 = first segment10 = last segment11 = middle segment[ D/C(1b) | P(1b) | SI(2b) | SN(12b or 18b, MSB first) | (SO if SI≠00) | Data field ]
[ D/C(1b) | CPT(3b) | ACK_SN(12b or 18b) | E1(1b) | padding ]
[ NACK_SN | E1 | E2 | E3 ] × N (variable number of NACK entries)
[ SOstart(16b) | SOend(16b) ] (present when E2=1)
[ NACK range(8b) ] (present when E3=1)
000 for STATUS PDU (only value defined in Rel-19)| Field | Size | Description |
|---|---|---|
| D/C | 1 bit | 0=control PDU, 1=data PDU |
| P | 1 bit | Poll bit — request STATUS report |
| SI | 2 bits | Segmentation Info: 00=complete, 01=first, 10=last, 11=middle |
| SN | 6/12/18 bits | Sequence Number (mode/config dependent) |
| SO | 16 bits | Segment Offset — byte position of first byte of segment |
| CPT | 3 bits | Control PDU Type (STATUS PDU = 000) |
| ACK_SN | 12/18 bits | Acknowledgement SN |
| E1 | 1 bit | Extension: 1 = NACK_SN+E1+E2+E3 follows |
| E2 | 1 bit | Extension: 1 = SOstart+SOend follows |
| E3 | 1 bit | Extension: 1 = NACK range follows |
| NACK_SN | 12/18 bits | Negatively acknowledged SN |
| SOstart | 16 bits | Start byte offset of missing segment |
| SOend | 16 bits | End byte offset of missing segment (0xFFFF = last byte) |
| NACK range | 8 bits | Number of consecutive NACKed SNs |
| R | 1 bit | Reserved = 0 |
| Variable | Init | Description |
|---|---|---|
| TX_Next | 0 | SN to assign to next new AMD PDU |
| TX_Next_Ack | 0 | Lower edge of TX window; SN of next expected ACK |
| POLL_SN | 0 | Highest SN submitted when poll was set |
| PDU_WITHOUT_POLL | 0 | Counter: AMD PDUs sent since last poll |
| BYTE_WITHOUT_POLL | 0 | Counter: bytes sent since last poll |
| RETX_COUNT | 0 | Per-SDU retransmission counter |
| Variable | Init | Description |
|---|---|---|
| RX_Next | 0 | Lower edge of RX window; first not-completely-received SN |
| RX_Next_Highest | 0 | Highest received SN + 1 |
| RX_Highest_Status | 0 | Highest SN allowed in ACK_SN field of STATUS PDU |
| RX_Next_Status_Trigger | — | SN after the one that triggered t-Reassembly |
| RX_Next_Discard_Trigger | — | SN after the one that triggered t-RxDiscard (if configured) |
| Variable | Init | Description |
|---|---|---|
| TX_Next | 0 | SN for next UMD PDU containing a segment |
| Variable | Init | Description |
|---|---|---|
| RX_Next_Reassembly | 0 | Earliest SN still pending reassembly |
| RX_Next_Highest | 0 | Highest received SN + 1; upper edge of reassembly window |
| RX_Timer_Trigger | — | SN after the one that triggered t-Reassembly |
| Constant | SN bits | Value |
|---|---|---|
| AM_Window_Size | 12-bit | 2048 |
| AM_Window_Size | 18-bit | 131072 |
| UM_Window_Size | 6-bit | 32 |
| UM_Window_Size | 12-bit | 2048 |
Window arithmetic: all SN comparisons use modular arithmetic:
| Timer | Entity | Purpose |
|---|---|---|
| t-PollRetransmit | AM TX | If poll ACK not received → retransmit |
| t-Reassembly | AM RX, UM RX | Gap detected → trigger status/discard after timeout |
| t-StatusProhibit | AM RX | Rate-limit STATUS PDU transmission |
| t-RxDiscard | AM RX | Discard AMD PDUs older than threshold (optional) |
All timer values configured by RRC via TS 38.331.
NTN note: t-Reassembly must be set large enough to accommodate the RTT:
| Parameter | Mode | Description |
|---|---|---|
| sn-FieldLength | UM, AM | SN bit width: UM=6 or 12; AM=12 or 18 |
| t-PollRetransmit | AM | Timer value |
| pollPDU | AM | Poll after every N PDUs |
| pollByte | AM | Poll after every N bytes |
| maxRetxThreshold | AM | Max retransmissions before RLF notification to upper layer |
| t-Reassembly | UM, AM | Reassembly timer value |
| t-StatusProhibit | AM | STATUS PDU rate limiter |
| t-RxDiscard | AM | Optional RX discard timer |
| stopReTxDiscardedSDU | AM | Stop retransmitting when PDCP discards SDU |
for each SDU from PDCP:
assign SN = TX_Next to each UMD PDU segment
if UMD PDU contains last segment of SDU:
TX_Next = (TX_Next + 1) mod UM_modulus
set SI field: 00=complete, 01=first, 10=last, 11=middle
set SO = byte offset of segment within SDU
on receive UMD PDU:
if no SN in header (SI=00):
deliver immediately to PDCP
elif SN in [RX_Next_Highest - UM_Window_Size, RX_Next_Reassembly):
discard (too old)
else:
place in reception buffer
→ run reassembly logic (§5.2.2.2.3)
→ manage t-Reassembly
on t-Reassembly expiry:
advance RX_Next_Reassembly past gap
discard all segments with SN < RX_Next_Reassembly
restart t-Reassembly if still gaps present