This article covers the MAC-NR layer of the 5G NR attach walkthrough. We will examine every MAC-NR subheader and control element on one UE, from Msg3 โ sent while the UE is still anonymous โ to the last scheduled transmission.
๐ก Read the walkthrough and the diagram side by side. Open the interactive diagram (or PDF) in a split-screen window so the captions stay in view as you read. In Edge, Chrome, or Firefox, right-click the link and pick your browser's split-screen option (Edge labels it "Open link in split screen window"). On macOS, prefer Chrome or Firefox โ Safari has no in-browser split screen. Otherwise, open the diagram in a new tab and snap the two windows side by side.
Where MAC sits
MAC appears in both planes of the 5G radio stack, so it gets both pictures. Read them as two views of one thing, not as two MACs.
Control plane โ signaling
sequenceDiagram
accTitle: 5G NR control-plane protocol stack, MAC highlighted
accDescr: The control-plane layers, top of stack to bottom. NAS spans the UE and the AMF, passing transparently through the gNB. RRC, PDCP, RLC, MAC and PHY each span the UE and the gNB. MAC, the subject of this article, is highlighted.
participant UE
participant gNB
participant AMF
Note over UE,AMF: NAS
Note over UE,gNB: RRC
Note over UE,gNB: PDCP
Note over UE,gNB: RLC
Note over UE,gNB: MAC
Note over UE,gNB: PHY
The 5G NR control-plane stack, with MAC highlighted. MAC sits between RLC above and PHY below, and talks to its peer MAC entity in the gNB. NAS passes transparently through the gNB to the AMF.
User plane โ data
sequenceDiagram
accTitle: 5G NR user-plane protocol stack, MAC highlighted
accDescr: The user-plane layers, top of stack to bottom. SDAP, PDCP, RLC, MAC and PHY each span the UE and the gNB. Below them, the N3 interface, GTP-U carrying the QoS Flow Identifier, spans the gNB and the UPF. MAC, the subject of this article, is highlighted.
participant UE
participant gNB
participant UPF
Note over UE,gNB: SDAP
Note over UE,gNB: PDCP
Note over UE,gNB: RLC
Note over UE,gNB: MAC
Note over UE,gNB: PHY
Note over gNB,UPF: N3 ยท GTP-U (QFI)
The 5G NR user-plane stack, with MAC highlighted. MAC occupies the same position, under RLC and above PHY, but the layer at the top of the stack is SDAP rather than RRC. Below the radio stack, an N3 box (GTP-U carrying the QFI) spans the gNB and the UPF.
The two MAC boxes are the same entity
This is where MAC differs from the layers above it, and the distinction is easy to miss because the two diagrams look symmetrical.
PDCP and RLC run one entity per bearer. A UE with a signaling bearer and a data bearer genuinely has two PDCP entities and two RLC entities, each with its own sequence-number space โ which is why the PDCP and RLC companions each walk two separate diagrams, one per bearer.
MAC runs one entity per UE. The MAC box in the control-plane picture and the MAC box in the user-plane picture are not two instances of a layer; they are the same scheduler, drawn twice because the stack above it differs. Everything from both planes arrives at it, and it packs them into the same transport blocks. The figure below redraws the two stacks as the funnel they actually are.
flowchart TD
accTitle: Two radio bearers converging on one MAC entity
accDescr: Two parallel chains feed one MAC entity. The signaling chain runs RRC to a PDCP entity to an RLC entity, and reaches MAC on logical channel ID 1. The data chain runs SDAP to a second PDCP entity to a second RLC entity, and reaches MAC on logical channel ID 4. Each chain has its own sequence-number space. Both arrive at a single MAC entity, one per UE, keyed on C-RNTI 0x8000, which multiplexes them into shared transport blocks and passes them to PHY.
subgraph SRB["Signaling radio bearer โ SRB 1"]
RRC["RRC"] --> PDCP1["PDCP entity<br/>own SN space"] --> RLC1["RLC entity<br/>own SN space"]
end
subgraph DRB["Data radio bearer โ DRB 1"]
SDAP["SDAP"] --> PDCP2["PDCP entity<br/>own SN space"] --> RLC2["RLC entity<br/>own SN space"]
end
RLC1 -->|"LCID 1"| MAC["<b>MAC โ one entity per UE</b><br/>keyed on C-RNTI 0x8000"]
RLC2 -->|"LCID 4"| MAC
MAC --> PHY["PHY<br/>shared transport blocks"]
The same two planes redrawn as one funnel, with this capture's own bearers. RRC and SDAP each sit on top of their own PDCP and RLC entities, but both chains end at a single MAC entity, which tells them apart only by the LCID on each subheader. Frame 4 on the walk below is this picture in one transport block.
That single MAC box at the bottom of the funnel is why this page has one diagram and one session, keyed on the C-RNTI rather than on a bearer: there is only one MAC conversation to follow. It carries signaling and user data together, told apart solely by the logical-channel ID on each subheader โ and the walk below is full of frames that do exactly that.
What MAC does
MAC โ Medium Access Control (TS 38.321) is the layer that decides who transmits, when, and how much. Everything above it hands down packets and assumes airtime exists. MAC is where airtime actually gets allocated, and where the several independent streams sharing one radio link get packed into the fixed-size blocks the physical layer can carry.
We will see the following MAC functions in this capture:
Identification. Before the network has agreed which UE it is talking to, MAC runs the contention-resolution exchange that turns an anonymous random-access attempt into a UE with its own C-RNTI (Cell Radio Network Temporary Identifier) โ the short handle the cell uses to address one connected device.
Multiplexing. A transport block โ one transmission's worth of bits โ can carry SDUs from several logical channels plus MAC's own control messages, each introduced by a subheader that names what follows. Assembling and taking apart that concatenation is MAC's core mechanic.
Reporting. The scheduler in the gNB cannot see inside the UE. So the UE tells it, in MAC control elements that ride along with ordinary data: how much is still queued (the Buffer Status Report) and how much transmit power is still in reserve (the Power Headroom Report).
Everything MAC does is in the clear. The capture is genuinely ciphered โ NEA2 (AES) on the access stratum โ but ciphering is a PDCP function that starts below the PDCP header, so LCIDs, lengths, control elements and padding all read without keys.
Important items to understand the flow:
Field
Meaning
LCID
Logical Channel ID, 6 bits. Values 1โ32 name a dedicated logical channel (a bearer's traffic); the common control channel sits outside that range, as LCID 0 on the downlink and LCID 52 on the uplink; everything else from 33 up names a control element or padding (TS 38.321 Tables 6.2.1-1 and 6.2.1-2). The meaning is direction-specific โ LCID 61 is a Short BSR going up and a Timing Advance Command coming down.
Subheader
The per-SDU header inside a MAC PDU: reserved bits, a format bit, the LCID, and โ for a variable-length SDU โ an SDU Length. Reading a MAC PDU is walking this chain.
BSR
Buffer Status Report. A control element saying how many bytes are still queued after this transmission, as a 5-bit index into a table of byte ranges (TS 38.321 ยง6.1.3.1).
LCG
Logical Channel Group, 0โ7. A BSR reports per group, not per channel; RRC assigns each logical channel to a group.
PHR
Power Headroom Report. How much transmit power the UE has left below its configured maximum โ the scheduler's cue that it can widen the grant or must not.
TA
Timing Advance Command. A 6-bit relative adjustment, centered on 31, that keeps this UE's uplink arriving inside the cell's symbol boundary.
Padding
LCID 63. A transport block is a fixed size once granted, so whatever the scheduler over-allocated must be filled. How much padding a link burns is a direct measure of how well the scheduler guessed.
The conversation we're following
๐ก Where this diagram comes from. This page follows one session out of the full attach walkthrough. VisualEther โ the tool that decoded this capture and generated the diagrams here โ splits a trace into per-protocol sessions and names each one; this is the one it labels mac-ue/timeout/00002, keyed on C-RNTI 0x8000.
MAC sees everything: every RRC message, every RLC PDU, every user-plane packet in this capture crossed the air inside one of these transport blocks.
The session begins at frame 2 rather than frame 1 because frame 1 is the Random Access Response, addressed to RA-RNTI 0x0500 rather than to a UE identity. It ends at frame 146 because the next frame in the capture is 32.45 seconds later, past the 30-second idle timeout that closes the session โ hence the timeout bucket in the name.
Here are the statistics for the 144 frames of the MAC session we are following:
Uplink
Downlink
Frames
68
76
Logical-channel SDUs
38 on LCID 4, 24 on LCID 1, 2 on LCID 52
29 on LCID 4, 26 on LCID 1, 2 on LCID 0
Control elements
66 Short BSR, 37 Single-Entry PHR
23 Timing Advance, 2 Contention Resolution
Padding subheaders
57, carrying 30955 bytes
64, carrying 0 bytes
Keep the last row in mind as you read the walk. The uplink threw away 30955 bytes on padding; the downlink threw away none โ on the same link, under the same rules. What frame 3 told the scheduler explains why the two directions differ so sharply.
Two RRC connections share this session. MAC sessions are keyed on C-RNTI alone, and the cell handed 0x8000 straight back out to a second UE context: UEId 1 runs frames 2 to 129, UEId 2 runs frames 131 to 146. The Random Access Response that opens the second connection โ frame 130 โ is excluded for the same reason frame 1 is.
One last thing before the walk: the diagram's 475 arrows are not 475 subheaders. The diagram draws each control element twice โ once on its own, with its fields expanded, and once in place, showing where it sat inside the MAC PDU. That doubles the 66 Short BSRs, the 37 PHRs and the 2 Contention Resolution elements in the table above, so 105 arrows are the same 105 elements seen a second time. Timing Advance Commands are drawn once. Subtract the repeats and the session's real content is 370 MAC subheaders.
The walk
Frames 2 and 3 โ winning the right to be addressed
Frame 2 is Msg3, and the UE is still anonymous. The subheader says LCID 52, which on the uplink shared channel means CCCH of size 48 bits (TS 38.321 Table 6.2.1-2) โ the only logical channel a UE may use before the network has agreed who it is. There is no length field, because 48 bits is the length: six bytes, 1b34056b1846, decoding as an RRC RRCSetupRequest whose ue-Identity is the random value b34056b184 and whose establishmentCause is mo-Signalling.
Behind it, 24 bytes of padding. The Random Access Response sized the grant that carried Msg3, before anyone knew how large the UE's first message would be.
Nothing so far singles this UE out. Several devices can pick the same preamble in the same slot, receive the same grant, and transmit Msg3 on top of one another.
Frame 2, Msg3: one CCCH subheader with no length field, six bytes of RRCSetupRequest, and 24 bytes of padding. Expand the MAC-NR layer to see the LCID 52 subheader and the random ue-Identity the UE picked for itself.
Frame 3 is Msg4, and it resolves that โ 0.708 ms later. The gNB sends a UE Contention Resolution Identity control element (LCID 62, TS 38.321 Table 6.2.1-1) whose six-octet payload is 1b34056b1846: a byte-for-byte echo of what the UE just sent.
TS 38.321 ยง5.1.5 states the rule plainly. A UE receiving this element compares it with the CCCH SDU it transmitted in Msg3. On a match, it declares contention resolution successful, stops ra-ContentionResolutionTimer, and โ for a random access started from idle โ promotes the Temporary C-RNTI it was given in the Random Access Response into its own C-RNTI. Every UE that sent a different Msg3 sees a mismatch, loses, and starts again.
One thing to note: the Random Access Response assigns Temporary C-RNTI 0x1001, yet every frame from Msg3 onward is stamped C-RNTI 0x8000 in the capture's own MAC-NR context. The promotion is not visible as a change in the RNTI field. You read contention resolution from the identity echo, not from the identifier.
And multiplexed behind that control element, in the same transport block: LCID 0 โ CCCH on the downlink โ carrying a 214-byte SDU, which is the RRC RRCSetup. Contention resolution and connection setup are unrelated procedures at two different layers, and MAC delivers both in one transmission because a MAC PDU is simply a concatenation of independently labeled subheaders (TS 38.321 ยง6.1.2).
Note the order: control element first, SDU second. That is the downlink rule. The uplink's is the mirror image, and the next frame shows it.
Frame 3, Msg4: the UE Contention Resolution Identity control element (LCID 62) echoing 1b34056b1846, followed by the LCID 0 subheader carrying the 214-byte RRCSetup. Control element first, SDU second โ the downlink ordering rule.
Frame 4 โ the complete multiplexing repertoire, in one PDU
The first uplink after contention resolution, 28.259 ms later, contains four subheaders:
LCID 1, a 108-byte SDU โ SRB 1's signaling traffic. Inside it, Wireshark reads an RLC-AM PDU with SN=0, wrapping PDCP SN=0, wrapping an RRC rrcSetupComplete, wrapping a NAS Registration Request. Five layers in 108 bytes โ MAC, RLC, PDCP, RRC and NAS โ and MAC sees none of the four above it: to MAC this is an opaque octet string that arrived on logical channel 1.
A Short BSR on Logical Channel Group 0, buffer-size index 0 โ which TS 38.321 ยง6.1.3.1 defines as literally BS = 0.
A Single-Entry PHR (LCID 57, TS 38.321 ยง6.1.3.8) with Power Headroom index 57 and Pcmax index 52, which the dissector expands to 26 dB <= PH < 28 dB and 22 dBm <= Pcmax,f,c < 23 dBm.
508 bytes of padding.
That is one logical-channel SDU, two control elements, and padding โ MAC's entire repertoire in a single transport block, in the first frame after the connection exists.
.1.. .... = Polling Bit:Status report is requested
..00 .... = Segmentation Info:Data field contains all bytes of an RLC SDU (0x0)
.... 0000 0000 0000 = Sequence Number:0
AM Data:000010c41fc00825c7e0197a0a3f4067e004119000bf200f110fe0041c23456782e02f07071003d2649aa0f140e68b0e3db267aa6e528f19f031481846dcff0608e4ea6c11174838a62b9778f1371225af3c59959a3e4349e912b7302ed47d9cb36886e2c06000000000
Frame 4's full MAC PDU: four subheaders in one uplink transport block. Expand the RLC, PDCP, RRC and NAS layers to see the 108-byte SDU unwrap all the way to a Registration Request.
Two details in that list repay attention.
The first BSR asks for nothing โ and that is correct, not broken. The UE had one RLC PDU queued, the grant took it whole, and MAC assembled both into the same PDU. By the time the buffer-size field was filled in, the buffer it describes had already been emptied into the very frame carrying it. A BSR is a snapshot of what is left over, not of what is being sent.
And the control elements come after the SDU, not before it. TS 38.321 ยง6.1.2 puts uplink control elements after all SDUs and before the padding, and downlink control elements before all SDUs. Compare frame 3, where the Contention Resolution element came first. Both orders hold across all 144 frames of this session without a single exception, and where a BSR and a PHR appear together, the BSR always comes first.
Power headroom, for its part, is the gap between the power the UE is permitted to use and the power it actually used. A large positive headroom tells the scheduler it can widen the grant or use denser modulation; a headroom near zero says the UE is at the wall and a bigger grant would only produce errors. It is the power-domain twin of the BSR: the BSR says how much I have to send, the PHR says how hard I can push. All 37 PHRs in this session report the identical pair of indices โ nothing about this UE's power situation changes for the whole capture.
Frames 21 to 29 โ the scheduling loop, and what it costs
This is the run that teaches the Buffer Status Report, because it is the only place in the session where the UE has a real backlog, and you can watch it drain.
Frame 21 โ the first BSR that asks for something. LCG 0, buffer-size index 16, which the level table reads as 1038 < BS <= 1446 bytes still queued after this transmission. The UE has been asked for its radio capabilities; the answer is far too large for one grant, and RLC has cut it up. The data SDU in this frame is 611 bytes; the BSR alongside says roughly a kilobyte and a half is still waiting.
Frame 22 โ index 13, 5.992 ms later.384 < BS <= 535 left. The scheduler granted, the UE sent 619 bytes, the buffer shrank by roughly a grant's worth. Note that 619: it is the largest logical-channel SDU the uplink ever carries in this session, and frames 51, 79 and 96 all reach the same figure.
Frame 23 โ index 0, 0.999 ms later. The capability report is out. Nothing is queued. Three grants, three reports, and the scheduler now knows it can stop.
Frames 25 to 29 โ except it does not stop. Five consecutive uplink transport blocks, spaced exactly 1.000 ms apart, each carrying a Short BSR that reports zero and then padding โ and not one logical-channel SDU between them. Frame 25's padding is 621 bytes, and 18 uplink frames in this session carry exactly that figure. (Frame 27 also carries a PHR, so it pads with 618 instead.)
Set 621 beside the 619-byte maximum SDU and the picture completes itself: the gNB offers one grant size over and over, whether or not the UE has anything to put in it. MAC cannot decline a grant and cannot send a short transport block, so it sends the only thing it has โ a Short BSR โ and fills the rest.
The gNB cannot see the UE's buffer; it can only see reports about that buffer's recent past, and it must commit airtime before the report it is acting on can be confirmed. Over-granting is the cheaper mistake, so over-granting is what you get. 23 of the 68 uplink frames in this session carry no logical-channel data whatsoever.
Frame 38 โ where a Logical Channel Group comes from
A 165-byte SDU on LCID 1, decoding to an RRC Reconfiguration. Two entries in it matter to MAC:
The group assignment is the field to hold on to. A Buffer Status Report does not report per logical channel โ it reports per group โ and this frame is where the mapping is decided. From here on, a BSR naming LCG 1 is talking about the data bearer and one naming LCG 0 is talking about signaling. Every LCG 1 report in the session appears after this frame.
Note also what the message does not contain: no mac-CellGroupConfig. MAC itself is never reconfigured after frame 3, which is the subject of the next section.
Frame 41 opens LCID 4 โ a 55-byte SDU on the logical channel frame 38 just created, carrying an RLC-AM PDU on DRB 1 with an 18-bit sequence number, a PDCP PDU, and an SDAP header with QoS Flow Identifier 2. To MAC, this is logical channel 4 rather than logical channel 1: same subheader format, same multiplexing rules, same control elements. Only the number changed. From here, 38 uplink and 29 downlink subheaders carry LCID 4.
Frames 50 and 78 โ five subheaders, and the biggest ask
Frame 50 is the busiest PDU shape in the session. Three LCID 4 SDUs โ 3 bytes of RLC status, then 67 bytes, then 542 bytes โ followed by a Short BSR and a Single-Entry PHR, with no padding subheader at all. Five subheaders, and only 13 of the 144 frames get that far.
Its BSR is the first on Logical Channel Group 1, index 16 โ 1038 < BS <= 1446 bytes queued on the data bearer, because frame 38 put LCID 4 in that group. This is how grouping assists the scheduler: it now knows not just how much the UE has to send but what kind, so signaling backlog and user-plane backlog arrive as separately numbered reports.
Frame 78 is the largest thing the UE ever asks for. LCG 1, index 17 โ 1446 < BS <= 2014 bytes still queued, the highest index anywhere in the session. Follow it forward: frame 79 reports 16, frame 80 reports 14, frame 81 reports 0. Four grants to clear a two-kilobyte backlog, at roughly one grant per millisecond โ and then frames 82, 83, 85, 86 and 87 are the same over-granted, BSR-plus-padding blocks that followed frame 23. The pattern is not specific to signaling. It repeats every time a burst ends.
Frames 90 to 111 โ the downlink, which never wastes a byte
Turn the link around, and the numbers change completely.
Frame 90 carries a 1226-byte SDU whole, with a zero-byte padding subheader behind it. Frame 102 carries 90 bytes with no padding subheader at all โ 12 downlink frames in this session end exactly where their SDU does. Frame 109 is the largest MAC SDU in the capture: 1438 bytes on LCID 4, a single subheader in a single transport block, no control element, no padding. Frame 110 completes it with 69 bytes and starts the next with 1367, two RLC sequence numbers in flight at once, told apart by nothing but their subheader lengths. Frame 111 carries 140 and then 578 and closes the burst.
More than three kilobytes in three transmissions, and nothing wasted. The uplink's ceiling, meanwhile, is 619 bytes.
Frames 6 to 127 โ a metronome with nothing left to time
Threaded through everything above is a control element that does nothing at all, on a perfect schedule.
LCID 61 on the downlink is the Timing Advance Command (TS 38.321 ยง6.1.3.4): one byte, carrying a 2-bit TAG ID and a 6-bit command. Timing advance is how a cell keeps every UE's uplink arriving inside the same symbol boundary despite different propagation delays โ the further away the UE, the earlier it must transmit.
There are 23 of them in this session, and every single one carries TAG 0 and the value 31. TS 38.213 ยง4.2 defines this element's value as a relative adjustment centered on 31, so 31 means no change.
Frames 6, 33, 34, 35, 45, 46, 60, 61, 65, 74, 88, 93, 94, and then 120 through 127 are the 21 commands of the first connection, and every consecutive interval among them falls between 599.957 ms and 600.032 ms. Frames 120 to 127 are eight of them back to back with no other traffic on the link at all.
Now, read the configuration the connection was given in frame 3: tag-Config sets tag-Id 0 with timeAlignmentTimerinfinity. A Timing Advance Command restarts that timer (TS 38.321 ยง5.2), but a timer set to infinity never expires, so there is nothing to restart.
Frames 128 and 129 โ RLC retransmission seen at MAC level
Frame 128 is the RRC Release: a 10-byte SDU on LCID 1, alone in its transport block โ no BSR, no PHR, not even a padding subheader. Ten bytes granted, ten bytes sent.
Frame 129 is the identical PDU again, 44.894 ms later. The cause of duplicate transmission is one layer up: RLC-AM polled with frame 128, got no status report back, and its t-PollRetransmit timer fired. From MAC's point of view, a second, unrelated 10-byte SDU arrived on logical channel 1.
That is worth keeping as a diagnostic habit. A repeated MAC SDU is rarely a MAC event.
What frame 3 told the scheduler
The RLC companion to this page ends on a spec default that nothing in the trace ever configures. MAC is the opposite case, and it is the more satisfying one: the RRCSetup in frame 3 carries a complete mac-CellGroupConfig, in the clear (nested inside a 209-octet masterCellGroup, if you want to see how it got there), and everything you have just read is that configuration playing out. Nothing after frame 3 touches it โ frame 38's reconfiguration carries no mac-CellGroupConfig at all.
Configured in frame 3
What the 144 frames show
periodicBSR-Timer sf1 โ one subframe, the shortest the enumeration offers
A Short BSR on 66 of the 68 uplink transmissions. The only two exceptions are frames 2 and 131, the two Msg3s, which carry nothing but a CCCH SDU.
retxBSR-Timer sf80
Not separately observable: with a periodic BSR already pending every millisecond, no retransmission trigger can be told apart from the periodic one.
23 Timing Advance Commands on TAG 0, every one carrying 31 โ on a timer that can never expire.
drx-Config absent
No discontinuous reception. The UE listens continuously; nothing in the trace is ever deferred to a wake-up.
Read the first row against frames 25 to 29, and the five-in-a-row BSR burst stops looking like a scheduler bug. periodicBSR-Timer at sf1 means a periodic BSR is pending essentially every millisecond; a BSR only transmits when a grant exists to carry it; and a grant existed every millisecond through that stretch. The trace is doing precisely what frame 3 told it to.
The third row is the same logic in the power domain. phr-Tx-PowerFactorChange dB1 would trigger a report whenever path loss moved by more than a decibel โ but the Power Headroom index sits at 57 in all 37 reports, and index 57 is a two-decibel-wide bucket (26 dB <= PH < 28 dB), so nothing in the trace suggests it ever fires. The only trigger left is phr-PeriodicTimer at sf10, and sure enough, no two PHRs in the session land closer than 9.988 ms apart. The gaps run much wider than 10 ms whenever the UE has no grant to put a report on, which is why the session holds 37 PHRs against 66 BSRs.
Which leaves the question the padding row of the earlier table posed: why does the uplink waste 30955 bytes while the downlink wastes zero?
Not because the directions run different rules โ they run identical ones. Because they have different information, the gNB sizes a downlink transport block against a buffer it owns and can read directly. Hence it never allocates more than it has: 64 downlink padding subheaders in this session, all of them the bare one-byte LCID 63 with nothing after it, and 12 downlink frames with no padding subheader at all. The uplink grant, by contrast, is sized from a Buffer Status Report that described the past โ and MAC must fill whatever arrives, exactly. Padding is not waste the UE chose. It is the visible residue of a control loop that has to guess.
The later connections
The full capture holds three RRC connections on the same cell. This session covers two of them, because MAC sessions are keyed on C-RNTI alone and the cell handed 0x8000 back out.
The second connection opens at frame 131, 3196.459 ms after the last frame of the first, with another LCID 52 CCCH transmission. Frame 132's Contention Resolution Identity echoes 0838468acf04 โ not the 1b34056b1846 of frame 3. That difference is the proof this is a genuinely new random access rather than a continuation: the identity is whatever Msg3 the UE actually sent this time, and a new random value produces a new echo. The MAC-NR context field agrees, stamping UEId 2 from here on.
Every interaction from the first connection repeats. Frame 132's 214-byte RRCSetup carries the same mac-CellGroupConfig โ periodicBSR-Timer sf1, phr-PeriodicTimer sf10, timeAlignmentTimer infinity, no drx-Config. Frame 133's uplink is frame 4's four-subheader pattern: a 54-byte LCID 1 SDU, a Short BSR reading zero, a PHR reading the identical index 57 and index 52, and 562 bytes of padding. Frames 135 and 144 are two more Timing Advance Commands, 600.017 ms apart, both carrying 31. Frames 145 and 146 are another RRC Release and another RLC-driven repeat of it, 44.915 ms later.
The third connection is outside this session. It begins 32.45 seconds after frame 146 โ past the 30-second idle timeout that defines the session boundary โ so the diagram ends mid-retransmission rather than at anything the protocol would call an ending.
Takeaways
Contention resolution is an identity echo, not an identifier change. The gNB replays the UE's own Msg3 bytes back at it; the UE that recognizes them wins.
A subheader chain is the whole MAC PDU format. One transport block carried a logical-channel SDU, a BSR, a PHR, and 508 bytes of padding in frame 4 โ four subheaders, four independent things, one transmission. Uplink puts control elements last, downlink puts them first, and both orders held across all 144 frames without exception.
A BSR reports the leftovers. 55 of 66 reports here say zero, because the grant that carried the report also carried the data it would have described. When a BSR is non-zero, watch the index fall across consecutive frames โ 16, then 13, then 0 โ and you are watching the scheduling loop close.
The LCID space is direction-specific.LCID 61 is a Short BSR going up and a Timing Advance Command coming down. Reading a MAC trace without tracking direction will mislead you within a dozen frames.
Padding measures the scheduler's uncertainty. 30955 bytes wasted on the uplink against zero on the downlink, on the same link, with the same rules โ because one side can read its own buffer and the other has to be told about it after the fact.
Where this sits in the stack
This page follows one layer of a much larger trace. The layers around it tell different parts of the same story:
Decrypting a 5G NR radio capture โ how the trace was opened up in the first place, and why MAC stays readable even when the payloads are not.
Try it on your own capture
Every arrow in this diagram was decoded and captioned by VisualEther from a raw Wireshark PCAP โ including the session split that isolated one UE's MAC entity from the rest of the cell. Point it at your own 5G, LTE, or IMS trace and read it the same way.
This site uses privacy-first, cookieless analytics (Cloudflare Web Analytics) and sets
no tracking or advertising cookies. A small number of strictly-necessary cookies are used
by our hosting platform to keep your session working. See our
Privacy & Cookies page for the full list.