MAC PDU, Subheaders & MAC CEs in 5G NR
How SDUs, MAC Control Elements and padding are packed into a transport block.
The physical layer will accept exactly one transport block per HARQ process per transmission occasion, of exactly one size, chosen by the scheduler from a table TS 38.214 cl. 5.1.3.2. MAC's job is to fill that block completely and to make the result parseable by a peer that was told nothing about what is inside it. Those two requirements together produce the whole design: a flat concatenation of self-describing units, plus padding to make the total land on the transport block size with no slack.
Contents
- 01What a MAC PDU Is For, and Why Every Byte Has a Subheader
- 02The subPDU: the Only Unit MAC Actually Handles
- 03The Subheader, All Six Shapes
- 04LCID on DL-SCH: the Complete Codepoint Space
- 05LCID on UL-SCH: the Complete Codepoint Space
- 06eLCID and the Two-Octet Extended Space
- 07subPDU Ordering, and Why It Is Asymmetric
- 08Padding, and the Single-Byte Case
- 09How a Receiver Walks a PDU -- and What Happens When It Cannot
- 10The Control Element Catalogue
- 11Bit Layouts of the CEs You Will Actually Meet
- 12What Each CE Tells You When You See It in a Log
- 13What Control Costs: Overhead Arithmetic
- 14Failure Modes and What Each One Means
- 15Where the Configuration Comes From
- 16Illustrative Message Traces
- 17Release Deltas: Rel-15 to Rel-18
- 18Reading MAC PDUs in Logs: a Checklist
- 19Glossary
- 20References
1. What a MAC PDU Is For, and Why Every Byte Has a Subheader
The physical layer will accept exactly one transport block per HARQ process per transmission occasion, of exactly one size, chosen by the scheduler from a table TS 38.214 cl. 5.1.3.2. MAC's job is to fill that block completely and to make the result parseable by a peer that was told nothing about what is inside it. Those two requirements together produce the whole design: a flat concatenation of self-describing units, plus padding to make the total land on the transport block size with no slack.
There is no MAC header in the sense that IP or Ethernet has one. There is no PDU-level length, no version, no checksum, no next-header pointer and no field that says how many pieces follow. A receiver starts at offset zero, reads one octet, and works out from that octet alone what to do with the next few. It repeats until it runs out of transport block. Everything good and everything fragile about MAC decoding follows from that.
The pieces MAC concatenates are of two kinds. MAC SDUs come from above: one RLC PDU per logical channel, opaque to MAC. MAC Control Elements are generated by MAC itself and consumed by the peer MAC: no RRC message, no ASN.1, no acknowledgement, no retransmission of their own beyond whatever HARQ gives them. A MAC CE is the cheapest signalling in NR, and that cheapness is why so much of the fast control loop -- timing advance, buffer status, power headroom, carrier activation, beam selection, DRX -- was put here rather than in RRC.
The reason to care about the exact packing rules is not academic. A MAC CE that the network sent and the UE did not act on looks identical, in most logs, to a MAC CE the network never sent -- unless you can read the octets. Two thirds of the "UE ignored our command" investigations in practice resolve to an ordering rule, a padding rule, or a codepoint the decoder on one side of the link did not know.
The companion 06 Channel Mapping document introduces the LCID field and the subheader in the context of which channel carries what. This document is the authoritative treatment: every subheader shape including the Rel-16 extensions, both complete codepoint tables, the ordering and padding rules, and each control element with its trigger and layout.
2. The subPDU: the Only Unit MAC Actually Handles
A MAC PDU consists of one or more MAC subPDUs TS 38.321 cl. 6.1.2. A subPDU is a subheader plus at most one of: a MAC SDU, a MAC CE, or padding. That is the entire grammar. There is no nesting, no optional second payload, and no subPDU that carries two things.
| subPDU contains | Subheader shape | Length known from | Example |
|---|---|---|---|
| A MAC SDU | R/F/LCID/L (2 or 3 octets) | The L field | An RLC PDU on DTCH, LCID 4, L = 132 |
| A variable-size MAC CE | R/F/LCID/L, or with an eLCID escape | The L field | Long BSR (UL LCID 62); TCI States Activation/Deactivation (DL LCID 53) |
| A fixed-size MAC CE | R/LCID (1 octet), or with an eLCID escape | The codepoint itself -- the receiver must already know the CE | Timing Advance Command (DL LCID 61, 1 octet payload) |
| A zero-size MAC CE | R/LCID (1 octet) | Nothing follows; the subheader is the whole subPDU | DRX Command (DL LCID 60); Configured Grant Confirmation (UL LCID 55) |
| An UL CCCH SDU | R/LCID (1 octet) | The codepoint: LCID 52 means 48 bits, LCID 0 means 64 bits | RRCSetupRequest in MSG3 |
| Padding | R/LCID (1 octet), LCID 63 | Implicit -- everything to the end of the transport block | The last subPDU of almost every real PDU |
Table 1. The six things a subPDU can be. Note the third and fifth rows: two cases where the length is carried by prior knowledge rather than by a field, which is exactly where decoders break.
A single MAC SDU is never split across two subPDUs, and a subPDU never spans two transport blocks. If an RLC PDU does not fit, RLC segments it and hands MAC a smaller PDU -- MAC does not fragment. This is why the L field is enough: whatever it says is entirely present in this transport block. See the companion 09 LCP document for how the size handed to RLC is decided.
3. The Subheader, All Six Shapes
Every subheader begins with the same two bit positions and a 6-bit LCID. What follows the LCID depends on what the LCID means, which the receiver has to know in advance. Four shapes existed in Rel-15; Rel-16 added two more by turning two LCID values into escapes.
| Shape | Octets | Bit layout | Used for | How the receiver knows |
|---|---|---|---|---|
| A | 2 | R(1) F=0(1) LCID(6) | L(8) | Any SDU or variable-size CE up to 255 octets | LCID is a variable-size codepoint; F = 0 |
| B | 3 | R(1) F=1(1) LCID(6) | L(16) | A single SDU longer than 255 octets -- common on high-throughput DRBs | LCID is a variable-size codepoint; F = 1 |
| C | 1 | R(1) R(1) LCID(6) | Fixed-size and zero-size MAC CEs; the UL CCCH SDU | LCID is a fixed-size codepoint of known length |
| D | 1 | R(1) R(1) LCID = 63 | Padding, always the last subPDU | LCID 63 is reserved for exactly this |
| E (Rel-16) | 2 or 3 | R/R/LCID=34 | eLCID(8) | (L) | A control element in codepoints 64 .. 319 | LCID 34 is an escape; the eLCID octet gives the real codepoint |
| F (Rel-16) | 3 or 4 | R/R/LCID=33 | eLCID(16) | (L) | A control element in codepoints 320 .. 65 855 | LCID 33 is an escape; two octets give the real codepoint |
Table 2. Subheader shapes, TS 38.321 cl. 6.1.2. Nothing in the octets distinguishes A/B from C/D except the LCID value, which is why the codepoint tables in the next two sections are the real parsing specification.
The F bit is not a general format flag. It exists only in shapes A, B and the variable-size eLCID shapes, and it says one thing: whether L is 8 or 16 bits wide. In shapes C and D the same bit position is a reserved bit that must be zero. A log that prints "F = 1" for a Timing Advance Command subheader is either showing you a corrupt octet or printing a field that does not exist at that position.
4. LCID on DL-SCH: the Complete Codepoint Space
Six bits, 64 codepoints, and Rel-15 spent all but twelve of them. The structure is worth noticing: SDU identities occupy the bottom, control elements the top, and the escapes sit at 33 and 34, immediately above the logical channel range so that no future logical channel can ever be added without a version break.
| LCID | Meaning | Size on the wire | Fixed / variable |
|---|---|---|---|
| 0 | CCCH | Subheader with L; the SDU is RRCSetup or RRCReject | Variable |
| 1 – 32 | Identity of a logical channel (DCCH or DTCH) | Subheader with L, then the RLC PDU | Variable |
| 33 | Extended LCID field, two octets (Rel-16) | Escape; codepoint = 320 + value | -- |
| 34 | Extended LCID field, one octet (Rel-16) | Escape; codepoint = 64 + value | -- |
| 35 – 46 | Reserved | Largely still reserved through Rel-18; new downlink CEs went into the extended space instead | -- |
| 47 | Recommended bit rate | 2 octets | Fixed |
| 48 | SP ZP CSI-RS Resource Set Activation/Deactivation | 2 octets | Fixed |
| 49 | PUCCH spatial relation Activation/Deactivation | 3 octets | Fixed |
| 50 | SP SRS Activation/Deactivation | Variable -- depends on the number of resources in the set | Variable |
| 51 | SP CSI reporting on PUCCH Activation/Deactivation | 2 octets | Fixed |
| 52 | TCI State Indication for UE-specific PDCCH | 2 octets | Fixed |
| 53 | TCI States Activation/Deactivation for UE-specific PDSCH | Variable -- one bit per candidate TCI state | Variable |
| 54 | Aperiodic CSI Trigger State Subselection | Variable -- one bit per trigger state | Variable |
| 55 | SP CSI-RS / CSI-IM Resource Set Activation/Deactivation | Variable | Variable |
| 56 | Duplication Activation/Deactivation | 1 octet | Fixed |
| 57 | SCell Activation/Deactivation (four octets) | 4 octets | Fixed |
| 58 | SCell Activation/Deactivation (one octet) | 1 octet | Fixed |
| 59 | Long DRX Command | 0 octets -- subheader only | Fixed |
| 60 | DRX Command | 0 octets -- subheader only | Fixed |
| 61 | Timing Advance Command | 1 octet | Fixed |
| 62 | UE Contention Resolution Identity | 6 octets (48 bits) | Fixed |
| 63 | Padding | 0 octets of subheader payload; fills the rest of the TB | -- |
Table 3. DL-SCH LCID codepoints, TS 38.321 Table 6.2.1-1, with the size class that decides which subheader shape carries them. The companion 06 Channel Mapping document gives the same table from the channel-mapping angle.
Codepoint 63 is padding in both directions, and codepoints 59-62 in the downlink collide numerically with 59-62 in the uplink (truncated and full BSRs). LCID is only meaningful together with the direction. A decoder configured for the wrong direction will happily turn a Short BSR into a Long DRX Command with no complaint at all -- both are valid fixed-size codepoints and both parse cleanly.
5. LCID on UL-SCH: the Complete Codepoint Space
The uplink table has the same shape and one structural oddity: CCCH appears twice, at 0 and 52, for the two possible sizes. That exists purely so a CCCH SDU can use a 1-octet subheader with no length field -- in MSG3 and MSGA, where every bit is expensive, the codepoint carries the length.
| LCID | Meaning | Size on the wire | Release |
|---|---|---|---|
| 0 | CCCH of size 64 bits (the CCCH1 channel) | 8 octets, no L field. Carries RRCResumeRequest1 | Rel-15 |
| 1 – 32 | Identity of a logical channel (DCCH or DTCH) | Subheader with L, then the RLC PDU | Rel-15 |
| 33 | Extended LCID field, two octets | Escape; codepoint = 320 + value | Rel-16 |
| 34 | Extended LCID field, one octet | Escape; codepoint = 64 + value | Rel-16 |
| 35 – 44 | Reserved | -- | -- |
| 45 | Truncated Sidelink BSR | Variable | Rel-16 |
| 46 | Sidelink BSR | Variable | Rel-16 |
| 47 | Pre-emptive BSR | Variable -- Long-BSR-shaped | Rel-16 (IAB) |
| 48 | LBT failure (four octets) | 4 octets | Rel-16 (NR-U) |
| 49 | LBT failure (one octet) | 1 octet | Rel-16 (NR-U) |
| 50 | BFR (Beam Failure Recovery) | Variable -- bitmap plus one octet per failed cell | Rel-16 |
| 51 | Truncated BFR | Variable | Rel-16 |
| 52 | CCCH of size 48 bits | 6 octets, no L field. RRCSetupRequest, RRCResumeRequest, RRCReestablishmentRequest, RRCSystemInfoRequest | Rel-15 |
| 53 | Recommended bit rate query | 2 octets | Rel-15 |
| 54 | Multiple Entry PHR (four octets) | Variable -- 4-octet bitmap then 1-2 octets per reported cell | Rel-15 |
| 55 | Configured Grant Confirmation | 0 octets -- subheader only | Rel-15 |
| 56 | Multiple Entry PHR (one octet) | Variable -- 1-octet bitmap then 1-2 octets per reported cell | Rel-15 |
| 57 | Single Entry PHR | 2 octets | Rel-15 |
| 58 | C-RNTI | 2 octets | Rel-15 |
| 59 | Short Truncated BSR | 1 octet | Rel-15 |
| 60 | Long Truncated BSR | Variable | Rel-15 |
| 61 | Short BSR | 1 octet | Rel-15 |
| 62 | Long BSR | Variable -- bitmap then one octet per reported LCG | Rel-15 |
| 63 | Padding | Fills the rest of the TB | Rel-15 |
Table 4. UL-SCH LCID codepoints. The Rel-16 assignments in 45-51 are the ones most likely to differ between the spec version you are reading and the decoder you are using -- confirm them against TS 38.321 Table 6.2.1-2 of the release in question.
Two uplink codepoints have no payload at all and are therefore invisible in any log that prints only "bytes of MAC CE": Configured Grant Confirmation (55) and, in the downlink, DRX Command (60) and Long DRX Command (59). If you are chasing a configured grant that the network believes is not active, or a UE that will not wake up, look for a single octet -- 0x37, 0x3C, 0x3B respectively -- and nothing after it.
6. eLCID and the Two-Octet Extended Space
By the end of Rel-15 the downlink table had twelve free codepoints and the uplink had seventeen, against a Rel-16 work programme that added beam-failure reporting, LBT failure reporting, IAB power and guard-symbol signalling, positioning, multi-TRP beam management and unified TCI. Reusing reserved values was not an option, because a receiver that meets an unrecognised fixed-size codepoint cannot find the next subheader -- there is no length to skip. So Rel-16 spent two of the remaining codepoints on escapes.
What the escape bought, exactly.
Native 6-bit LCID: 64 codepoints, 0 .. 63
One-octet eLCID via LCID 34: 256 values -> codepoints 64 .. 319
Two-octet eLCID via LCID 33: 65 536 values -> codepoints 320 .. 65 855
Total addressable: 64 + 256 + 65 536 = 65 856
Cost per use: one extra octet for the one-octet form, two for the two-octet form. Against a 2-octet CE that is a 50% or 100% overhead on the control element -- which is why the escape is spent on rare, infrequent CEs and never on a logical channel identity. Logical channels remain capped at 32 per direction per MAC entity.
As of Rel-18 the two-octet space is entirely reserved: nothing has been assigned there yet. Every real extended control element lives in the one-octet space reached through LCID 34. The two-octet escape exists so that the next twenty years of MAC CEs do not require another format change.
| Extended-space CE | Dir | Release | Size | What it is for |
|---|---|---|---|---|
| Enhanced SCell Activation/Deactivation (1-octet and 4-octet Ci forms) | DL | Rel-17 | Variable | Activates an SCell and names the TCI state to use on it, so the UE does not have to run a fresh beam search after activation |
| Unified TCI States Activation/Deactivation | DL | Rel-17 | Variable | Rel-17 unified TCI: one indication drives both DL and UL beams |
| Enhanced TCI States Activation/Deactivation for UE-specific PDSCH | DL | Rel-17 | Variable | Multi-TRP: two TCI states per codepoint |
| Duplication RLC Activation/Deactivation | DL | Rel-16 | Variable | Per-RLC-leg duplication control, rather than the whole-DRB switch of LCID 56 |
| Positioning Measurement Gap Activation/Deactivation Command | DL | Rel-17 | Fixed | Opens a gap for PRS measurement without an RRC reconfiguration |
| Provided Guard Symbols / Desired Guard Symbols | DL / UL | Rel-16 | Variable | IAB: the DU tells the MT how many symbols it needs to switch between parent and child links, and the MT asks for more |
| Timing Case Indication / Case-6 Timing Request | DL / UL | Rel-17 | Fixed | IAB timing mode selection |
| Desired IAB-DU TX Power Adjustment | UL | Rel-17 | Variable | IAB-MT asks its parent to change the collocated DU's transmit power |
| Enhanced BFR / Enhanced Truncated BFR | UL | Rel-17 | Variable | Per-TRP beam failure reporting, for multi-TRP PDCCH |
| Multiple Entry Configured Grant Confirmation | UL | Rel-16 | Variable | Confirms several configured grants at once (Rel-16 allows up to 12 per BWP) |
| SP Positioning SRS Activation/Deactivation | DL | Rel-17 | Variable | Turns semi-persistent positioning SRS on and off |
| Sidelink Configured Grant Confirmation | UL | Rel-16 | Fixed | NR sidelink equivalent of LCID 55 |
Table 5. Representative contents of the one-octet extended space. Codepoints are deliberately not listed: assignments are added from the top of the range downward as features land, and differ between releases. Read them from Table 6.2.1-1b (DL) or 6.2.1-2b (UL) of the exact TS 38.321 version you are decoding against.
The signature of a decoder that predates the extended space is very specific: one plausible subPDU, then garbage. The decoder prints LCID 33 or 34 as reserved, guesses a length, lands mid-payload, and then reports a run of impossible subheaders -- LCIDs in the reserved range, absurd L values, a padding subheader in the middle of the PDU. That pattern is a decoder version problem, not a radio problem, and no amount of retuning will change it.
7. subPDU Ordering, and Why It Is Asymmetric
The order of subPDUs inside a MAC PDU is fixed by the spec, and it is different in the two directions TS 38.321 cl. 6.1.2.
| Direction | Required order | Why |
|---|---|---|
| DL-SCH | MAC CEs first, then MAC SDUs, then padding | The UE can act on the control element -- change beam, activate an SCell, adjust timing, go to sleep -- while it is still working through the data in the same PDU. Putting the CE last would mean waiting for a full transport block of RLC processing before a 1-octet command takes effect. |
| UL-SCH | MAC SDUs first, then MAC CEs, then padding -- except that a Pre-emptive BSR is placed before all MAC SDUs | A buffer status report must describe the buffer as it will be after this PDU leaves, so the SDUs have to be selected first. Building the SDUs first and the report second is the natural implementation order, and the wire order follows it. The Pre-emptive BSR is the exception because it reports data that has not arrived yet, so it does not depend on what was packed. |
Table 6. Ordering rules. The uplink exception for Pre-emptive BSR came in with Rel-16 IAB; verify it against the release you are decoding.
Within each of those groups the order is not arbitrary either, but it is decided by a different rule: the relative priority of control elements and logical channel data, defined for the uplink in TS 38.321 cl. 5.4.3.1.3 and covered in the companion 09 LCP document. The short version is that a C-RNTI MAC CE and UL-CCCH data sit above everything, a BSR included as padding sits below everything, and the rest fall between.
The ordering rule is a transmitter obligation, not a receiver requirement. A conformant receiver parses subPDUs in whatever order they arrive; it does not reject a PDU whose CEs are in the wrong place. So a vendor bug that emits an uplink CE before the SDUs will not produce an error anywhere -- it will produce a BSR that describes a buffer including data the gNB is about to receive, and therefore a persistent, small over-estimate of the UE's queue. That shows up as chronically slightly over-sized grants, never as a failure.
8. Padding, and the Single-Byte Case
A transport block size comes from a table; the sum of the subPDUs MAC wants to send almost never equals one of those sizes. The difference is padding, and it goes at the end. NR has no equivalent of LTE's front-placed one- and two-byte padding: the padding subPDU is last, always.
- Zero padding. The subPDUs fill the block exactly. There is no padding subheader at all -- not a padding subheader with L = 0, nothing. This is the normal case for a large data-only PDU where RLC was asked for exactly the right segment size.
- One octet of padding. The padding subPDU is a single R/LCID subheader with LCID 63 and no payload. One octet in, one octet of transport block consumed, nothing wasted on a length field. This is the single-byte case, and it is why the padding subheader has no L field: with one, one byte of slack would be unrepresentable.
- Two or more octets. One padding subheader, then padding octets to the end of the block. The receiver does not need to be told how many: LCID 63 means everything from here on.
Padding is not free space -- it is the trigger for a whole class of opportunistic reporting. If the padding remaining after a MAC PDU is built is at least the size of a Short BSR plus its subheader (2 octets), MAC replaces padding with a Padding BSR TS 38.321 cl. 5.4.5. The same logic drives the truncated BSR and truncated BFR formats. So the presence of a 1-octet padding subPDU and the presence of a padding BSR are mutually exclusive by construction, and seeing 6 octets of padding with a BSR pending is a genuine anomaly worth chasing.
One more rule that catches people: MAC does not transmit a PDU consisting only of a padding BSR and padding. If there is nothing else to send, the grant goes unused rather than being spent on a report the network can get another way.
9. How a Receiver Walks a PDU -- and What Happens When It Cannot
Three of the branches above are worth dwelling on, because each corresponds to a distinct log signature.
9.1 Unknown variable-size codepoint
The receiver does not recognise the LCID but the codepoint is in a range it knows to be variable-size, so it reads L and skips L octets. It has lost one subPDU and can continue. In a log this appears as a single "unknown LCID" line followed by correctly decoded subPDUs. Annoying, recoverable, usually a bearer that RRC configured on one side only.
9.2 Unknown fixed-size codepoint
The receiver does not recognise the LCID and there is no length field. It cannot skip, cannot resynchronise, and must discard the remainder of the transport block. Everything after that point is lost -- including, commonly, the data SDUs, since in the downlink CEs come first. One unknown control element costs the whole PDU.
9.3 Length field longer than the remaining transport block
An L value that runs past the end of the block means the parse has already gone wrong upstream -- a mis-parsed subheader, a wrong-direction codepoint table, or a corrupt octet that HARQ CRC should have caught but did not because the corruption is in the decoder's own byte accounting rather than on the air. The PDU is discarded.
Because there is no MAC-level integrity check, a MAC PDU that passes the transport-block CRC is assumed to be correctly formed. That assumption is what makes the parse cheap enough to run at 4 GHz of throughput, and it is why every failure in this section is silent at the physical layer. Correlate with HARQ statistics from the companion 05 HARQ document: if CRC pass rates are healthy and MAC decode is failing, the problem is in the codepoint tables, not on the radio.
10. The Control Element Catalogue
Every MAC CE in NR is listed below by function, with the LCID, the direction, whether the size is fixed, and -- the part that is hardest to find in the spec -- what actually causes one to be emitted. The clause numbers in the last column point at the procedure that triggers the CE, not at its format.
10.1 Identity, contention resolution and grant confirmation
| MAC CE | LCID | Dir | Size | What triggers it |
|---|---|---|---|---|
| UE Contention Resolution Identity | DL 62 | DL | 6 octets, fixed | MSG4 in contention-based Random Access. Echoes the first 48 bits of the UE's MSG3 CCCH SDU so the winner can recognise itself TS 38.321 cl. 5.1.5 |
| C-RNTI | UL 58 | UL | 2 octets, fixed | A UE that already has a C-RNTI performs Random Access (handover, TA recovery, beam failure). Sending the C-RNTI in MSG3 is the contention resolution -- the gNB answers on the C-RNTI itself TS 38.321 cl. 5.1.4 |
| Configured Grant Confirmation | UL 55 | UL | 0 octets | The UE has activated or released a Type 2 configured grant via PDCCH and must confirm it TS 38.321 cl. 5.8.2 |
| Multiple Entry Configured Grant Confirmation | eLCID | UL | Variable | Rel-16: same, when several configured grants changed state together |
Table 7. Identity CEs. The C-RNTI CE is the one people forget exists: its presence in a MSG3 tells you immediately that this was not an initial access.
10.2 Uplink reporting: buffer, power, rate
| MAC CE | LCID | Dir | Size | What triggers it |
|---|---|---|---|---|
| Short BSR | UL 61 | UL | 1 octet, fixed | Regular, Periodic or Padding BSR when exactly one LCG has data TS 38.321 cl. 5.4.5 |
| Long BSR | UL 62 | UL | Variable | Regular or Periodic BSR when more than one LCG has data |
| Short Truncated BSR | UL 59 | UL | 1 octet, fixed | Padding BSR where only one octet fits but more than one LCG has data |
| Long Truncated BSR | UL 60 | UL | Variable | A Long BSR is called for but the space cannot hold every buffer size field |
| Pre-emptive BSR | UL 47 | UL | Variable | Rel-16 IAB: an IAB-MT reports data it expects to receive from a child node, so the parent can grant ahead of arrival |
| Single Entry PHR | UL 57 | UL | 2 octets, fixed | PHR triggered while only one serving cell has uplink configured TS 38.321 cl. 5.4.6 |
| Multiple Entry PHR (1-octet Ci) | UL 56 | UL | Variable | PHR with multiplePHR = true and no serving cell index above 7 |
| Multiple Entry PHR (4-octet Ci) | UL 54 | UL | Variable | PHR with a serving cell index above 7 to report |
| Recommended bit rate query | UL 53 | UL | 2 octets, fixed | The UE asks the network for a bit rate on one logical channel, gated by bitRateQueryProhibitTimer |
Table 8. Reporting CEs. All of these are covered in depth in the companion 10 BSR, PHR, SR document, including the buffer size and power headroom quantisation tables.
10.3 Timing, sleep and carrier control
| MAC CE | LCID | Dir | Size | What triggers it |
|---|---|---|---|---|
| Timing Advance Command | DL 61 | DL | 1 octet, fixed | The gNB has measured a timing error on a Timing Advance Group and issues a relative correction. Restarts timeAlignmentTimer TS 38.321 cl. 5.2 |
| DRX Command | DL 60 | DL | 0 octets | The gNB has nothing more for this UE in this on-duration and sends it to short DRX (or long, if short is not configured) TS 38.321 cl. 5.7 |
| Long DRX Command | DL 59 | DL | 0 octets | As above but forces the long cycle directly, skipping short DRX |
| SCell Activation/Deactivation (1 octet) | DL 58 | DL | 1 octet, fixed | Carrier aggregation state change for serving cell indices 1-7 TS 38.321 cl. 5.9 |
| SCell Activation/Deactivation (4 octets) | DL 57 | DL | 4 octets, fixed | As above, reaching indices 1-31 |
| Enhanced SCell Activation/Deactivation | eLCID | DL | Variable | Rel-17: activation that also carries the TCI state to use, cutting activation delay |
| Duplication Activation/Deactivation | DL 56 | DL | 1 octet, fixed | Turns PDCP duplication on or off per DRB without an RRC reconfiguration |
| Duplication RLC Activation/Deactivation | eLCID | DL | Variable | Rel-16: same at the granularity of an individual RLC leg |
| Recommended bit rate | DL 47 | DL | 2 octets, fixed | The network suggests a bit rate for one logical channel -- typically an answer to a query, used for rate-adaptive voice and video codecs |
Table 9. Timing, DRX and carrier CEs. See the companion 04 Timing Advance and 11 DRX documents for the procedures these drive.
10.4 Beam, CSI and SRS control
| MAC CE | LCID | Dir | Size | What it does |
|---|---|---|---|---|
| TCI States Activation/Deactivation for UE-specific PDSCH | DL 53 | DL | Variable | Selects which of up to 128 configured TCI states are active -- DCI then picks one of up to 8 active states with 3 bits |
| TCI State Indication for UE-specific PDCCH | DL 52 | DL | 2 octets, fixed | Names the single TCI state for one CORESET. There is no DCI-level choice for control, so this CE is the beam decision |
| Aperiodic CSI Trigger State Subselection | DL 54 | DL | Variable | Narrows the aperiodic CSI trigger state list so the DCI CSI request field can address it |
| SP CSI reporting on PUCCH Activation/Deactivation | DL 51 | DL | 2 octets, fixed | Starts or stops a semi-persistent CSI report on PUCCH |
| SP CSI-RS / CSI-IM Resource Set Activation/Deactivation | DL 55 | DL | Variable | Starts or stops the reference signals a SP CSI report measures on |
| SP ZP CSI-RS Resource Set Activation/Deactivation | DL 48 | DL | 2 octets, fixed | Activates zero-power CSI-RS -- REs the UE must treat as muted, used to protect another cell's CSI-RS |
| SP SRS Activation/Deactivation | DL 50 | DL | Variable | Starts or stops semi-persistent SRS, and carries the spatial relation for each resource in the set |
| PUCCH spatial relation Activation/Deactivation | DL 49 | DL | 3 octets, fixed | Selects the beam for one PUCCH resource |
| Unified TCI States Activation/Deactivation | eLCID | DL | Variable | Rel-17: one joint or separate DL/UL TCI indication for the whole cell |
Table 10. Beam and CSI CEs. Note the split of labour: for data, the CE activates a candidate set and DCI chooses; for control, the CE chooses outright. That is why a PDCCH beam change is a MAC round trip and a PDSCH beam change is not.
10.5 Failure recovery and channel access
| MAC CE | LCID | Dir | Size | What triggers it |
|---|---|---|---|---|
| BFR | UL 50 | UL | Variable | Rel-16: beam failure detected on one or more SCells. Reports which cells failed and, per cell, a candidate beam if one was found above rsrp-ThresholdBFR TS 38.321 cl. 5.17 |
| Truncated BFR | UL 51 | UL | Variable | Same event, but the grant or padding cannot hold every candidate octet |
| Enhanced BFR / Enhanced Truncated BFR | eLCID | UL | Variable | Rel-17: per-TRP reporting, for a UE with two CORESET pools |
| LBT failure (1 octet / 4 octets) | UL 49 / 48 | UL | Fixed | Rel-16 NR-U: consistent listen-before-talk failure on one or more cells. A channel-access failure, not a radio failure |
| Desired Guard Symbols | eLCID | UL | Variable | Rel-16 IAB: the MT asks the parent for more switching time |
| Provided Guard Symbols | eLCID | DL | Variable | Rel-16 IAB: the parent tells the MT what it will actually get |
Table 11. Recovery CEs, all post-Rel-15. Beam failure on the SpCell is not reported this way -- it uses Random Access. See the companion 12 Beam Failure Recovery document.
Beam failure recovery is split across two mechanisms and the split is a frequent source of confusion. SpCell beam failure triggers a contention-free Random Access on the candidate beam -- there is no CE, because the UE has no working control channel to send one on. SCell beam failure sends a BFR MAC CE on the SpCell, because the SpCell is still up. If you see BFR MAC CEs, the UE's primary link is healthy.
11. Bit Layouts of the CEs You Will Actually Meet
Five figures, covering the control elements that appear in ordinary traffic. The rest follow the same conventions: reserved bits are zero, multi-bit fields are big-endian within and across octets, and bitmaps index from bit 0 upward.
11.1 The small fixed-size CEs
| Field | CE | Bits | Range | Meaning |
|---|---|---|---|---|
| TAG ID | Timing Advance Command | 2 | 0 – 3 | Which Timing Advance Group this correction applies to. 0 is the primary TAG |
| Timing Advance Command | Timing Advance Command | 6 | 0 – 63 | Relative adjustment, not absolute: 31 means no change, and N_TA,new = N_TA,old + (value − 31) × 16 × 64 / 2^mu in T_c units TS 38.213 cl. 4.2 |
| UE Contention Resolution Identity | -- | 48 | any | The first 48 bits of the CCCH SDU the UE sent in MSG3, echoed verbatim |
| C-RNTI | C-RNTI CE | 16 | 0x0001 – 0xFFEF | The UE's existing C-RNTI, sent in MSG3 to identify itself without contention resolution |
Table 12. Fields of the small fixed-size CEs. The 31-is-zero encoding of the TA command is the most commonly mis-read field in MAC: a logged value of 31 is not a missing command.
Reading a relative TA command. A Timing Advance Command MAC CE with value 35, at 30 kHz SCS (mu = 1):
delta = (35 − 31) = +4 steps
step = 16 × 64 / 2^1 = 512 T_c, and T_c = 1/(480000 × 4096) s ≈ 0.509 ns
shift = 4 × 512 × 0.509 ns ≈ 1.04 us of additional advance
In distance that is about 156 m of extra one-way path -- the UE moved away, or the propagation path changed. Compare with the absolute 12-bit command in the RAR, which is a completely different encoding: see the companion 04 Timing Advance document.
11.2 SCell Activation/Deactivation
The SCell Activation/Deactivation CE is a complete state statement, not a delta. A gNB that wants to add SCell 3 to a UE already running SCells 1 and 2 must send a CE with C1 = C2 = C3 = 1. Sending C3 = 1 alone deactivates 1 and 2. In logs this appears as SCells mysteriously dropping when another is added, and the throughput signature -- a step down at the moment a carrier was supposedly added -- is unmistakable once you know to look for it.
11.3 The two TCI control elements
11.4 BFR and Truncated BFR
11.5 Multiple Entry PHR
The Multiple Entry PHR is the most structurally complicated CE in NR: a bitmap of one or four octets, then one or two octets per reported entry depending on a bit inside the entry itself. Its layout, the PH and P_CMAX,f,c encodings and the virtual-versus-real distinction are covered in full in the companion 10 BSR, PHR, SR document, which also gives the Single Entry PHR layout.
12. What Each CE Tells You When You See It in a Log
A control element in a trace is evidence about state you cannot see directly. This table is the inference, not the definition.
| When you see this CE | It tells you | And the next thing to check |
|---|---|---|
| UE Contention Resolution Identity (DL 62) | A contention-based RACH reached MSG4. The UE had no C-RNTI, so this was initial access, re-establishment or resume | Whether the echoed 48 bits match the UE's own MSG3. A mismatch is a lost contention, not a failure |
| C-RNTI CE (UL 58) | A RACH from a UE that already had a context -- handover, timing recovery after timeAlignmentTimer expiry, or an SR that ran out of attempts | What was running just before: T304 means handover, no timer means TA recovery or SR fallback |
| Timing Advance Command (DL 61) | The gNB measured an uplink timing error worth correcting on that TAG | The magnitude of (value − 31). A steady drip of ±1 is a healthy control loop; a sudden ±20 means the path changed |
| Short BSR with buffer size 0 | The UE has just emptied that LCG. This is the end-of-burst marker | That the network stops granting shortly after. Continued grants mean the BSR was not processed |
| Long BSR appearing where Short BSRs were normal | A second LCG became active -- a new bearer started carrying data | Which LCG appeared, and whether its logicalChannelGroup assignment matches the intent |
| Short/Long Truncated BSR | The UE wanted to report more than the available space allowed. Not an error -- but the report is incomplete | Whether truncation is chronic. Persistent truncation means grants are consistently too tight for the number of active LCGs |
| Single Entry PHR with a low headroom value | The UE is near its power ceiling on that carrier | Whether the scheduler reduced MCS or PRB count in response. If not, expect uplink HARQ failures |
| Multiple Entry PHR where Single Entry was normal | multiplePHR was configured, or a second uplink carrier was activated | The V bits: a virtual entry means the UE was not actually transmitting on that carrier and the number is a calculation, not a measurement |
| DRX Command (DL 60) / Long DRX Command (DL 59) | The scheduler explicitly released the UE early rather than letting drx-InactivityTimer run out | How much of the inactivity timer was left. Frequent early release is a sign the timer is configured too long for the traffic |
| SCell Activation/Deactivation (DL 57/58) | A carrier aggregation state change. Read the whole bitmap, not just the changed bit | The activation delay that follows -- the SCell is not usable immediately TS 38.133 cl. 8.3 |
| Duplication Activation/Deactivation (DL 56) | PDCP duplication was switched for at least one DRB, usually in response to a measurement or a reliability target | Whether both legs actually carry traffic afterwards. Duplication activated on a leg with no grant is invisible reliability |
| BFR / Truncated BFR (UL 50/51) | One or more SCells lost their beam, and the SpCell is still healthy | The AC bit. AC = 0 on every entry means the UE has no candidate at all, which usually precedes SCell release |
| LBT failure CE (UL 48/49) | NR-U only: the UE could not get channel access, repeatedly. Nothing is wrong with the radio link | The unlicensed channel occupancy, not the UE. This is an interference or coexistence question |
| Configured Grant Confirmation (UL 55) | The UE accepted a Type 2 configured grant activation or release | That the confirmation arrived at all. A missing one means the network and UE disagree about whether the grant is live |
| Recommended bit rate query (UL 53) / Recommended bit rate (DL 47) | An adaptive codec is negotiating rate with the network at MAC speed instead of via the application | Whether the queries are being answered. Unanswered queries usually mean the feature is unsupported at the gNB |
Table 13. Inference table. Every row here is something you can conclude from the presence of a control element without any other information in the log.
13. What Control Costs: Overhead Arithmetic
A small uplink grant, fully accounted. The UE sent a Scheduling Request; the gNB replies with a conservative grant. Transport block = 56 octets TS 38.214 Table 5.1.3.2-1.
Pending: a Regular BSR (3 LCGs with data) and a PHR (2 activated carriers), plus 200 octets of DTCH data.
Long BSR ....... subheader 2 + bitmap 1 + 3 buffer sizes = 6 octets
ME PHR ......... subheader 2 + bitmap 1 + 2 entries x 2 = 7 octets
-------------------------------------------------
Control total ................................. 13 octets (23%)
Left for the DTCH subPDU ...................... 43 octets
minus its own 2-octet subheader ............. 41 octets of data
So 20% of the UE's 200-octet burst goes out in a grant that spent a quarter of itself on reports. Repeat that at a 56-octet grant size and the burst takes five round trips instead of two. This is the whole argument for granting generously once after an SR rather than conservatively several times -- see the companion 08 Scheduling document.
| Transport block | Control carried | Control octets | Fraction | Practical consequence |
|---|---|---|---|---|
| 24 octets | Short BSR only | 2 | 8% | Fine. The typical padding-BSR case |
| 56 octets | Long BSR + ME PHR | 13 | 23% | Bad. Grant is too small for a UE that has just asked for capacity |
| 309 octets | Long BSR + ME PHR | 13 | 4% | Negligible. This is where reports should live |
| 1544 octets | Long BSR + ME PHR + 2 SDUs | 17 | 1% | Invisible |
| 56 octets | TA Command + DRX Command (DL) | 3 | 5% | Fine, but note both are 1-octet-payload CEs and still cost a subheader each |
Table 14. Control overhead against transport block size. Transport block sizes are illustrative values from the TBS table for common PRB/MCS combinations.
The design consequence runs the other way too. Because a fixed-size CE costs exactly one subheader octet and no length field, the marginal cost of adding MAC signalling to NR was almost zero, and that is why so many features that could have been RRC procedures were built as control elements instead. A beam switch that would take an RRCReconfiguration round trip -- tens of milliseconds, an ASN.1 encode and decode, and an acknowledgement -- takes 2 octets and one slot as a MAC CE.
14. Failure Modes and What Each One Means
| Failure | Detected by | What happens | Diagnostic pointer |
|---|---|---|---|
| Unknown fixed-size LCID | Receiving MAC, at parse time | The rest of the transport block is discarded. In the downlink that usually means the SDUs too, since CEs come first | A release or vendor mismatch. Check the UE capability exchange against the CEs the gNB is emitting; check whether the decoder knows the Rel-16 escapes (§6) |
| Unknown variable-size LCID | Receiving MAC | That one subPDU is discarded; L lets the parse continue | Usually a logical channel configured on one side only. Compare the LCIDs in PDUs against RLC-BearerConfig |
| LCID decoded with the wrong direction table | Nobody -- it parses cleanly | A Short BSR becomes a Long DRX Command, or a Long BSR becomes a UE Contention Resolution Identity | Impossible-looking CEs in the wrong direction. If a UE 'sent' a DRX Command, this is what happened |
| L field runs past the end of the transport block | Receiving MAC | PDU discarded | The parse went wrong earlier. Look at the previous subPDU, not this one |
| Padding subheader not last | Nobody -- everything after it is unreachable by definition | The subPDUs after the padding subheader are silently lost | A transmitter bug. The symptom is data or CEs that the sender logs and the receiver never sees, with no error on either side |
| MAC CE emitted before SDUs in the uplink | Nobody -- it is a transmitter obligation only | The BSR describes a buffer that still includes the data in this very PDU | Chronically over-sized grants and a buffer report that never quite reaches zero |
| Fixed-size CE truncated by the transport block | Receiving MAC, or nobody | Should not happen -- the transmitter must not start a CE it cannot finish. If it does, the receiver reads past the end | A TBS accounting bug in the transmitter. Correlate the sum of subPDU sizes against the TBS the DCI granted |
| SCell Activation CE read as a delta rather than a state | Nobody at MAC level; the throughput drop is the only symptom | Previously active SCells deactivate | A carrier count that falls when a carrier is added (§11.2) |
| Zero-length CE dropped by a log filter | Nobody | The CE was sent and acted on, but does not appear in any byte-count view of the trace | DRX Command, Long DRX Command, Configured Grant Confirmation. Search for the subheader octet, not for a CE payload |
| Transport block CRC passes but MAC decode fails | Receiving MAC | PDU discarded, no HARQ retransmission is requested -- HARQ already succeeded | The most diagnostic combination in this document: healthy HARQ plus failing MAC decode means a codepoint or format problem, never a radio problem |
Table 15. MAC PDU failure modes. Note how many are detected by nobody: MAC has no error reporting toward its peer, so a malformed PDU produces missing behaviour rather than an error message.
The single most useful diagnostic in this whole document: compare the sum of the subPDU sizes against the transport block size from the DCI. If they do not agree, the decode is wrong -- and whichever subPDU the shortfall begins at is where it went wrong. This one check separates "my decoder is confused" from "the network really did that", and it takes ten seconds.
15. Where the Configuration Comes From
MAC PDU format is not configurable -- it is fixed by the spec. What is configurable is which control elements are enabled, which logical channel identities exist, and the timers that make CEs fire. Those live in MAC-CellGroupConfig and RLC-BearerConfig inside the cell group configuration TS 38.331.
MAC-CellGroupConfig ::= SEQUENCE {
drx-Config SetupRelease { DRX-Config } OPTIONAL,
schedulingRequestConfig SchedulingRequestConfig OPTIONAL,
bsr-Config BSR-Config OPTIONAL,
tag-Config TAG-Config OPTIONAL,
phr-Config SetupRelease { PHR-Config } OPTIONAL,
skipUplinkTxDynamic BOOLEAN,
...,
[[ csi-Mask BOOLEAN OPTIONAL,
dataInactivityTimer SetupRelease { DataInactivityTimer } OPTIONAL ]],
[[ usePreBSR-r16 ENUMERATED {true} OPTIONAL,
schedulingRequestID-LBT-SCell-r16 SchedulingRequestId OPTIONAL,
lch-BasedPrioritization-r16 ENUMERATED {enabled} OPTIONAL,
schedulingRequestID-BFR-SCell-r16 SchedulingRequestId OPTIONAL ]],
...
}
RLC-BearerConfig ::= SEQUENCE {
logicalChannelIdentity LogicalChannelIdentity, -- INTEGER (1..32)
servedRadioBearer CHOICE {
srb-Identity SRB-Identity,
drb-Identity DRB-Identity
} OPTIONAL,
reestablishRLC ENUMERATED {true} OPTIONAL,
rlc-Config SetupRelease { RLC-Config } OPTIONAL,
mac-LogicalChannelConfig SetupRelease { LogicalChannelConfig } OPTIONAL,
...
}
TAG-Config ::= SEQUENCE {
tag-ToReleaseList SEQUENCE (SIZE (1..maxNrofTAGs)) OF TAG-Id OPTIONAL,
tag-ToAddModList SEQUENCE (SIZE (1..maxNrofTAGs)) OF TAG OPTIONAL
}
TAG ::= SEQUENCE {
tag-Id TAG-Id, -- INTEGER (0..3), the TAG ID field
timeAlignmentTimer TimeAlignmentTimer,
...
}Listing 1. Abridged from TS 38.331. ... marks omitted fields and extension markers. maxNrofTAGs is 4, which is why the TAG ID field in the Timing Advance Command CE is exactly 2 bits.
| Parameter | Where | Range | Typical | Effect on the PDU |
|---|---|---|---|---|
logicalChannelIdentity | RLC-BearerConfig | 1 – 32 | 1-3 for SRBs, 4+ for DRBs | Becomes the LCID in every subheader for that bearer |
logicalChannelGroup | LogicalChannelConfig | 0 – 7 | 0-3 | Decides which LCG a channel's data is reported under in a BSR, and hence whether a Short or Long BSR is used |
multiplePHR | PHR-Config | true / false | true with CA | Chooses between LCID 57 and LCID 54/56 for power headroom |
tag-Id | TAG-Config | 0 – 3 | 0 only, unless CA with mixed geography | The TAG ID field of the Timing Advance Command CE |
drx-Config | MAC-CellGroupConfig | SetupRelease | configured | Without it, a DRX Command CE is meaningless and the UE will ignore it |
usePreBSR | MAC-CellGroupConfig | true / absent | absent | Rel-16. Enables the Pre-emptive BSR CE, and with it the uplink ordering exception in §7 |
lch-BasedPrioritization | MAC-CellGroupConfig | enabled / absent | absent unless URLLC | Rel-16 intra-UE prioritisation; changes which subPDUs get built at all. See the companion 09 LCP document |
skipUplinkTxDynamic | MAC-CellGroupConfig | true / false | true | Lets the UE drop a grant it would otherwise fill entirely with padding -- directly reduces the number of padding-only PDUs you will see |
Table 16. Configuration that changes what a MAC PDU looks like on the wire.
16. Illustrative Message Traces
Illustrative trace. Field names and encodings follow 3GPP; the values are constructed for this document and are not a capture from any deployed or lab network.
16.1 A five-subPDU downlink MAC PDU, octet by octet
09:41:18.204 [MAC-DL] PDSCH, C-RNTI 0x4C0D, TBS 64 octets, HARQ pid 3, NDI 1
off hex binary decode
--- --- -------- --------------------------------------------------
0 3D 0011 1101 R=0 R=0 LCID=61 -> Timing Advance Command, fixed 1 oct
1 23 0010 0011 TAG ID=0 TA Command=35 -> +4 steps, ~1.04 us at 30 kHz
2 3A 0011 1010 R=0 R=0 LCID=58 -> SCell Activation/Deactivation, 1 oct
3 06 0000 0110 C7..C1 = 0000011, R=0 -> SCell 1 and SCell 2 ACTIVE,
SCells 3..7 DEACTIVE
4 34 0011 0100 R=0 R=0 LCID=52 -> TCI State Indication for UE-specific
PDCCH, fixed 2 oct
5 00 0000 0000 ServingCellId=0 CORESET ID bits 3..1 = 000
6 89 1000 1001 CORESET ID bit 0 = 1 -> CORESET 1; TCI State ID = 9
7 01 0000 0001 R=0 F=0 LCID=1 -> DCCH (SRB1), 8-bit length follows
8 16 0001 0110 L = 22 octets
9-30 .. (22 octets) RLC AM PDU -> PDCP -> RRCReconfiguration segment
31 04 0000 0100 R=0 F=0 LCID=4 -> DTCH (DRB1), 8-bit length follows
32 1A 0001 1010 L = 26 octets
33-58 .. (26 octets) RLC AM PDU -> PDCP -> SDAP -> IP
59 3F 0011 1111 R=0 R=0 LCID=63 -> Padding, to end of transport block
60-63 00 (4 octets) padding
accounting: 2 + 2 + 3 + 24 + 28 + 5 = 64 octets = TBS [consistent]
09:41:18.204 [MAC] applied TA +4 on TAG 0, restarted timeAlignmentTimer
09:41:18.204 [MAC] SCell 1, SCell 2 -> activated; activation delay pending
09:41:18.204 [MAC] CORESET 1 TCI state -> 9
09:41:18.205 [RLC] DCCH SDU (22) and DTCH SDU (26) delivered upwardListing 2. Three control elements and two SDUs in one 64-octet block. Note the accounting line: 64 octets of subPDU against a 64-octet TBS is the check described in §14.
Three separate state changes -- uplink timing, carrier aggregation and the PDCCH beam -- travelled in seven octets, ahead of the data, in a transport block whose main purpose was to carry an RRCReconfiguration fragment. Reconstructing this sequence from RRC messages alone would show none of it. This is why MAC-level tracing matters even when the question looks like an RRC question.
16.2 An uplink MAC PDU: data, a BSR, and padding
09:41:22.617 [MAC-UL] grant from DCI 0_1: TBS 68 octets, C-RNTI 0x4C0D,
HARQ pid 5, k2 = 4, PUSCH slot 1082.7
09:41:22.617 [MAC] LCP: Regular BSR pending (triggered 09:41:22.611)
DTCH LCID 4: 812 octets available
DCCH LCID 1: 0 octets
off hex binary decode
--- --- -------- --------------------------------------------------
0 04 0000 0100 R=0 F=0 LCID=4 -> DTCH (DRB1), 8-bit length
1 3E 0011 1110 L = 62 octets
2-63 .. (62 octets) RLC AM PDU, SO=0, 62-octet segment of a 812-octet SDU
64 3D 0011 1101 R=0 R=0 LCID=61 -> Short BSR, fixed 1 oct
65 4F 0100 1111 LCG ID=2 Buffer Size index=15 -> > 745 and <= 1038 oct
66 3F 0011 1111 R=0 R=0 LCID=63 -> Padding
67 00 0000 0000 1 padding octet
accounting: 64 + 2 + 2 = 68 octets = TBS [consistent]
09:41:22.617 [MAC] BSR sent -> cancel triggered BSR, restart periodicBSR-Timer
(812 - 62 = 750 octets still queued on LCG 2)
-- 750 falls in 5-bit level 15, whose range is 746 .. 1038.
-- Level 14 (536 .. 745) would UNDER-state it by 5 octets, so
-- the UE reports 15 and the gNB learns only 746 <= BS <= 1038.
09:41:22.617 [MAC] retxBSR-Timer restarted on grant receptionListing 3. One SDU, one Regular BSR, one octet of padding, exactly filling a 68-octet grant. The uplink order -- SDU first, CE second -- is what makes the reported buffer size describe the queue after this PDU.
Look at the buffer size reasoning in that trace. The UE has 750 octets queued and reports 5-bit level 15, whose range is 746 .. 1038 octets. The gNB now knows the queue to within 293 octets -- a 39% uncertainty. At level 25 the bucket is over 8 kB wide. A BSR is a bucket, never a byte count, and a scheduler that grants exactly the reported level will over-grant most of the time by construction. The full quantisation table and the 8-bit alternative are in the companion 10 BSR, PHR, SR document.
16.3 An extended-LCID control element
09:44:03.881 [MAC-DL] PDSCH, C-RNTI 0x4C0D, TBS 16 octets, HARQ pid 1
off hex binary decode
--- --- -------- --------------------------------------------------
0 22 0010 0010 R=0 R=0 LCID=34 -> one-octet eLCID escape
1 E6 1110 0110 eLCID = 230 -> codepoint 64 + 230 = 294
-- this decoder's Rel-17 table resolves 294 to
-- Enhanced SCell Activation/Deactivation, 1-octet Ci
2 06 0000 0110 C7..C1 = 0000011, R=0 -> activate SCell 1, SCell 2
3 80 1000 0000 entry for SCell 1: TCI state field present, id = 0
4 82 1000 0010 entry for SCell 2: TCI state field present, id = 2
5 3F 0011 1111 R=0 R=0 LCID=63 -> Padding
6-15 00 (10 octets) padding
accounting: 5 + 11 = 16 octets = TBS [consistent]
-- The same event through a decoder that predates the escape:
0 22 0010 0010 R=0 F=0 LCID=34 *** RESERVED ***
decoder assumes shape A and reads the next octet as L
1 E6 L = 230 octets -- but only 14 octets remain in the TB
-- --- PDU DISCARDED: length exceeds transport block
-- The SCells are never activated. Nothing is logged as an error on either
-- side. The gNB's scheduler proceeds as if two carriers are live.Listing 4. An extended-LCID CE decoded correctly, then the same octets through a decoder that does not know LCID 34. The failure is total and silent.
16.4 A failure: unknown fixed-size codepoint mid-PDU
09:52:47.115 [MAC-DL] PDSCH, C-RNTI 0x4C0D, TBS 96 octets, HARQ pid 7
CRC ....................... PASS -- HARQ succeeded
off hex binary decode
--- --- -------- --------------------------------------------------
0 3D 0011 1101 R=0 R=0 LCID=61 -> Timing Advance Command
1 21 0010 0001 TAG ID=0 TA Command=33 -> +2 steps [applied]
2 31 0011 0001 R=0 R=0 LCID=49 -> PUCCH spatial relation
Activation/Deactivation
*** codepoint not supported by this UE release ***
*** fixed-size CE: length is not on the wire ***
-- --- MAC: cannot determine subPDU length -> discard remainder of TB
-- --- octets 3..95 (93 octets) LOST, including:
-- --- one DCCH subPDU (RRCReconfiguration, 40 octets)
-- --- one DTCH subPDU (48 octets)
09:52:47.115 [MAC] no HARQ retransmission requested -- CRC passed
09:52:47.115 [RLC-DL] no SDU delivered
09:52:52.115 [RLC-DL] t-Reassembly expired, gap at SN 1204 -> STATUS PDU (NACK)
09:52:52.117 [RRC] T310 not started; RRCReconfiguration never arrived
09:53:07.118 [RRC] RRCReconfiguration not completed -> reconfiguration failureListing 5. One unsupported control element costs 93 octets, an RRCReconfiguration and, five seconds later, an RLC status report that looks like a radio problem. The CRC passed.
The give-away in that trace is the combination of CRC PASS with a missing SDU and no HARQ retransmission. If HARQ had failed, the block would have been retransmitted and the RRC message would have arrived late rather than never. A CRC pass followed by silence upward is a MAC parse failure, and the octet where it happened is in the log. Nothing about the radio needs investigating.
17. Release Deltas: Rel-15 to Rel-18
| Release | Change | Why it matters when reading MAC PDUs |
|---|---|---|
| Rel-15 | The subPDU model, four subheader shapes, both 64-codepoint LCID tables, and 24 control elements | Everything in §2-§5 and most of §10. If a decoder handles Rel-15 correctly it will parse the great majority of real traffic |
| Rel-16 | eLCID escapes at LCID 33 and 34, opening codepoints 64 .. 65 855 | The single most consequential format change since Rel-15. A decoder without it desynchronises on the first extended CE (§6, §16.3) |
| Rel-16 | SCell beam failure recovery: BFR and Truncated BFR CEs at UL LCID 50/51 | Beam failure becomes visible as a control element rather than only as a Random Access |
| Rel-16 | NR-U: LBT failure CEs at UL LCID 48/49 | A new class of uplink failure that is not a radio problem at all |
| Rel-16 | NR sidelink: Sidelink BSR and Truncated Sidelink BSR at UL LCID 45/46 | Uplink codepoints 45-51 stop being reserved. A Rel-15 decoder will call them reserved and desynchronise on the fixed-size ones |
| Rel-16 | IAB: Pre-emptive BSR (UL 47), Desired and Provided Guard Symbols, and the uplink ordering exception for Pre-emptive BSR | The first and only exception to "uplink CEs come after SDUs" (§7) |
| Rel-16 | Duplication RLC Activation/Deactivation, and Multiple Entry Configured Grant Confirmation, both in the extended space | Duplication control moves from per-DRB to per-leg; configured grants become plural |
| Rel-16 | Type 3 power headroom (SRS-based) in the PHR CEs | A PHR entry can now describe an SRS-only carrier. Check the entry type before reading the number |
| Rel-17 | Unified TCI and enhanced TCI CEs; Enhanced SCell Activation/Deactivation carrying a TCI state | Activation and beam selection merge into one CE, shortening SCell activation delay measurably |
| Rel-17 | Enhanced BFR and Enhanced Truncated BFR for per-TRP reporting | With two CORESET pools, "beam failure" is no longer one event per cell |
| Rel-17 | Positioning: SP Positioning SRS Activation/Deactivation and Positioning Measurement Gap Activation/Deactivation | Measurement gaps can now open and close without an RRC round trip |
| Rel-17 | IAB timing case CEs and Desired IAB-DU TX Power Adjustment | IAB nodes negotiate timing and power at MAC speed |
| Rel-18 | Further extended-space additions for network-controlled repeaters, multi-carrier and energy-saving features; no change to the subPDU or subheader model | The format has been stable since Rel-16. New CEs appear only as new codepoints in the extended space -- which is exactly what the escape was built for |
Table 17. MAC PDU and CE changes by release. Feature presence should always be confirmed against the UE capability exchange -- see the companion 26 UE Capability document.
There have been exactly two wire-format changes to the MAC PDU since Rel-15, and both are in Rel-16: the eLCID escapes, and the Pre-emptive BSR ordering exception. Everything else is new codepoints. That stability is the whole point of a self-describing subPDU: adding a control element does not touch the parser.
18. Reading MAC PDUs in Logs: a Checklist
1. Check the accounting first. Sum every subPDU -- subheaders, payloads, padding -- and compare against the transport block size from the DCI. If they disagree the decode is wrong, and the first subPDU where the running total goes bad is where it broke (§14).
2. Confirm the direction of the codepoint table. LCID 59-62 mean completely different things in each direction and both parse cleanly. If the decode looks impossible -- a UE that sent a DRX Command, a gNB that sent a BSR -- this is why.
3. Read the whole subheader, not just the LCID. The F bit only exists in shapes A and B. If your tool prints an F bit for a fixed-size CE, it is printing a reserved bit and you should not trust the rest of that line.
4. Look for LCID 33 and 34 before believing anything downstream. One unrecognised escape produces one plausible subPDU followed by nonsense. Check the decoder's spec version against the gNB's release (§6).
5. Verify the ordering. Downlink: CEs, then SDUs, then padding. Uplink: SDUs, then CEs, then padding, with Pre-emptive BSR the one exception. A violation is a transmitter bug that produces no error anywhere (§7).
6. Treat a CRC pass with nothing delivered upward as a MAC problem. No HARQ retransmission plus no SDU means the block decoded and the parse failed. Do not go looking at the radio (§16.4).
7. Read SCell Activation bitmaps in full. They are absolute state, not deltas. Compare against the set of SCells you believe were active before (§11.2).
8. Distinguish 1-octet padding from a padding BSR. If two or more octets of padding remain and no BSR was inserted, either no BSR was pending or the padding-BSR logic is not running -- the second is a real finding (§8).
9. Search for zero-length CEs by their subheader octet. DRX Command (0x3C), Long DRX Command (0x3B) and Configured Grant Confirmation (0x37) have no payload and are invisible to any payload-oriented filter.
10. Correlate every CE you see against the configuration that should have enabled it. A DRX Command to a UE with no drx-Config, a Multiple Entry PHR with multiplePHR absent, or a BFR CE with no schedulingRequestID-BFR-SCell are all configuration mismatches, and all of them look like UE misbehaviour until you check.
19. Glossary
| Term | Expansion | Meaning in this document |
|---|---|---|
| MAC PDU | Protocol Data Unit | The contents of exactly one transport block on DL-SCH or UL-SCH; a flat sequence of subPDUs with no PDU-level header |
| subPDU | -- | One subheader plus at most one payload. The only structural unit MAC has |
| MAC SDU | Service Data Unit | One RLC PDU handed down for one logical channel. Opaque to MAC |
| MAC CE | Control Element | MAC-generated signalling consumed by the peer MAC entity. No ASN.1, no acknowledgement of its own |
| LCID | Logical Channel ID | The 6-bit field that identifies what a subPDU contains. Meaningful only together with the direction |
| eLCID | Extended LCID | The Rel-16 one- or two-octet field reached through LCID 34 or 33, giving codepoints 64 .. 65 855 |
| L field | Length | 8 or 16 bits, present only for variable-size payloads; the F bit says which width |
| F bit | Format | Says whether L is 8 or 16 bits. Does not exist in the 1-octet subheader shapes |
| R bit | Reserved | Set to zero. Two of them in a 1-octet subheader, one in a 2- or 3-octet subheader |
| Padding | -- | LCID 63. Means "everything from here to the end of the transport block", so it carries no length and must be last |
| TAG | Timing Advance Group | A set of serving cells sharing one uplink timing correction; the 2-bit TAG ID field addresses up to four |
| LCG | Logical Channel Group | Up to eight groups over which BSR reports buffer occupancy. Set by logicalChannelGroup |
| TBS | Transport Block Size | The size MAC must fill exactly. Chosen by the scheduler from a table, not by MAC |
| TCI state | Transmission Configuration Indication state | A beam, expressed as a quasi-colocation relationship to a reference signal. Activated by CE, selected by DCI |
| BFR | Beam Failure Recovery | Here specifically the SCell reporting CE; SpCell recovery uses Random Access instead |
20. References
- 3GPP TS 38.321 -- NR MAC protocol specification. Clause 6.1.2 (MAC PDU for DL-SCH and UL-SCH, subPDU and subheader formats, ordering and padding), 6.1.3 (all MAC CE formats -- 6.1.3.1 BSR, 6.1.3.2 C-RNTI, 6.1.3.3 UE Contention Resolution Identity, 6.1.3.4 Timing Advance Command, 6.1.3.5/6 DRX Commands, 6.1.3.7 Configured Grant Confirmation, 6.1.3.8 Single Entry PHR, 6.1.3.9 Multiple Entry PHR, 6.1.3.10 SCell Activation/Deactivation, 6.1.3.11 Duplication Activation/Deactivation, 6.1.3.14/6.1.3.15 TCI CEs, 6.1.3.20 Recommended bit rate, 6.1.3.22/23 BFR), 6.2.1 (subheader formats), Tables 6.2.1-1 and 6.2.1-2 (LCID values), Tables 6.2.1-1a/-1b and -2a/-2b (eLCID values).
- 3GPP TS 38.321 -- the procedures that emit the CEs: clause 5.1.4/5.1.5 (Random Access, C-RNTI and Contention Resolution CEs), 5.2 (timing advance), 5.4.3.1 (logical channel prioritisation and CE priority order), 5.4.5 (BSR), 5.4.6 (PHR), 5.7 (DRX), 5.8.2 (configured grant confirmation), 5.9 (SCell activation), 5.17 (SCell beam failure recovery).
- 3GPP TS 38.331 -- RRC protocol specification.
MAC-CellGroupConfig,RLC-BearerConfig,LogicalChannelConfig,TAG-Config,PHR-Config,BSR-Config,DRX-Config. - 3GPP TS 38.213 -- Physical layer procedures for control. Clause 4.2 (timing advance application), clause 7.7 (power headroom definitions for Types 1, 2 and 3).
- 3GPP TS 38.214 -- Physical layer procedures for data. Clause 5.1.3.2 (transport block size determination -- the sizes MAC must fill exactly).
- 3GPP TS 38.133 -- Requirements for support of radio resource management. Clause 8.3 (SCell activation delay), and the power headroom and P_CMAX reporting ranges.
- 3GPP TS 38.300 -- NR overall description. Clause 6.2 and 6.4 for where MAC sits and what it is responsible for.
Companion documents in this set
- 03 Random Access -- the RAR MAC PDU, which uses a different subheader format entirely, and the UE Contention Resolution Identity and C-RNTI CEs in context.
- 04 Timing Advance -- what the 1-octet relative Timing Advance Command CE does to N_TA, and how it differs from the RAR's absolute command.
- 05 HARQ -- the transport block and CRC layer beneath everything here; essential for separating radio failures from parse failures.
- 06 Channel Mapping -- the LCID tables from the channel-mapping angle, and where logical channel identities come from.
- 08 Scheduling -- who chooses the transport block size MAC has to fill.
- 09 LCP -- how MAC decides which SDUs and which CEs go into a given grant, and the fixed CE priority order.
- 10 BSR, PHR, SR -- the BSR and PHR control elements in full, including the buffer size and power headroom quantisation tables.
- 11 DRX -- what the DRX Command and Long DRX Command CEs actually do.
- 12 Beam Failure Recovery -- the procedure behind the BFR CE, and the SpCell case that uses RACH instead.
- 26 UE Capability -- how to establish which control elements a particular UE will accept.