MAC-LTE in a Real VoLTE Capture: Random Access, LCID Multiplexing, BSR, and PHR

The MAC layer of the LTE attach and VoLTE walkthrough, followed on its own. MAC is the bottom of the stack: every RRC message, RLC PDU, and voice packet on the other pages crossed the air inside one of its transport blocks. This page reads UE 70's MAC entity through random access, the attach, and a stretch of call 1, with an annotated diagram that captions every MAC subheader.

💡 Read the walkthrough and the diagram side by side: open the interactive diagram in a split-screen window, or open it in a new tab and snap the two windows side by side.

Where MAC sits

MAC (Medium Access Control, TS 36.321) sits between RLC and the physical layer, in both the control plane and the user plane. The layers above it run one entity per radio bearer: UE 70 has a separate RLC and PDCP entity for SRB1, SRB2, the internet bearer, the IMS bearer, and each voice bearer. MAC runs one entity per UE. All those bearers end at it, and it tells them apart by a single number on each piece it carries: the logical channel ID, or LCID.

flowchart TD accTitle: UE 70's radio bearers converging on one MAC entity accDescr: Five bearers feed one MAC entity. SRB1 arrives on LCID 1 and SRB2 on LCID 2, both in logical channel group 0. DRB 1, the internet bearer, arrives on LCID 3 in group 3. DRB 2, the IMS signaling bearer, arrives on LCID 4 in group 2. DRB 3, call 1's voice, arrives on LCID 5 in group 1. The MAC entity, keyed on C-RNTI 70, multiplexes them into transport blocks for the physical layer. SRB1["SRB1 · RRC"] -->|"LCID 1 · LCG 0"| MAC SRB2["SRB2 · NAS"] -->|"LCID 2 · LCG 0"| MAC DRB1["DRB 1 · internet"] -->|"LCID 3 · LCG 3"| MAC DRB2["DRB 2 · SIP over IPsec"] -->|"LCID 4 · LCG 2"| MAC DRB3["DRB 3 · call-1 voice"] -->|"LCID 5 · LCG 1"| MAC MAC["<b>MAC: one entity per UE</b><br/>C-RNTI 70"] --> PHY["PHY<br/>one transport block per TTI"]
UE 70's bearers converging on one MAC entity. Each arrives on its own LCID and belongs to a logical channel group (LCG), which is what the Buffer Status Report counts. The voice bearer's LCID, 5, is call 1's; later calls use 6 to 10.

This page stays at the MAC level. What rides inside each LCID has its own page: the RLC PDUs on the RLC page, their PDCP layer on the PDCP page, the SIP and voice on the SIP page, and the RRC messages that configure all of this on the RRC page.

What MAC does

The radio carries one transport block per TTI (transmission time interval, 1 ms in LTE). MAC decides what goes into it. It has four main jobs:

Everything MAC does travels in the clear. Ciphering is a PDCP function, and here it is EEA0 anyway.

The fields

FieldMeaning
LCIDLogical Channel ID, 5 bits. 1–10 name a logical channel; the rest name CCCH, a control element, or padding. The meaning depends on direction (table below).
SubheaderOne per SDU, control element, or padding run: the LCID, and for a variable-size SDU, a length. All subheaders come first, then the bodies in the same order (TS 36.321 §6.1.2).
BSRBuffer Status Report: bytes still queued after this transport block is built, per LCG, as a 6-bit index into a table of byte ranges (Table 6.1.3.1-1).
LCGLogical Channel Group, 0–3. RRC puts each logical channel in a group; the BSR reports groups, not channels.
PHRPower Headroom Report: the UE's maximum transmit power minus the power the current grant needs, as a 6-bit index (TS 36.213 §5.1.1.2, TS 36.133 §9.1.8.4).
SRScheduling Request: a one-bit signal on PUCCH that asks for an uplink grant. It is a physical-layer signal, so it never appears in a MAC log.
PaddingLCID 31. A granted transport block has a fixed size, and whatever the UE doesn't fill becomes padding.

The LCIDs

TS 36.321 has one LCID table per direction. These are the rows that matter for UE 70, a Rel-12 device:

LCIDDownlink (Table 6.2.1-1)Uplink (Table 6.2.1-2)Seen for UE 70
0CCCHCCCHonce each way: Msg4 and Msg3
1–10logical channellogical channel1 SRB1, 2 SRB2, 3 DRB 1, 4 DRB 2, 5–10 the six voice bearers
26Long DRX CommandPower Headroom Report445 PHRs
27Activation/DeactivationC-RNTI—
28UE Contention Resolution IdentityTruncated BSR1 Contention Resolution, 0 Truncated BSR
29Timing Advance CommandShort BSR612 Short BSRs, 0 Timing Advance Commands
30DRX CommandLong BSR212 Long BSRs
31PaddingPaddingboth ways

The same number means different things in each direction: 29 is a Short BSR going up and a Timing Advance Command coming down. Read a MAC trace without tracking direction, and you will misread it.

The subheader

Most subheaders are one byte, followed by a length for SDUs of variable size:

packet accTitle: LTE MAC subheader with a 7-bit length field accDescr: Sixteen bits. One reserved bit, one F2 bit, one extension bit E, a five-bit logical channel ID, one format bit F, and a seven-bit length. 0: "R" 1: "F2" 2: "E" 3-7: "LCID (5 bits)" 8: "F" 9-15: "L (7 bits)"
MAC subheader with a 7-bit length (TS 36.321 §6.1.2). E says another subheader follows. A fixed-size control element or the last subheader stops after the first byte. SDUs over 127 bytes set F to 1 and use a 15-bit length instead. F2 was a reserved bit before Rel-13 and is 0 throughout.

Frame 985, UE 70's first voice uplink, shows a whole MAC PDU:

flowchart LR accTitle: Layout of the MAC PDU in frame 985 accDescr: Left to right. Subheader for LCID 29, the Short BSR. Subheader for LCID 5 with length 77. Subheader for LCID 31, padding. Then the Short BSR body, LCG 0 and buffer size 0. Then the 77-byte RLC UM PDU carrying voice. Then 435 bytes of padding. H1["Subheader<br/>LCID 29"] --> H2["Subheader<br/>LCID 5, L = 77"] --> H3["Subheader<br/>LCID 31"] --> C["Short BSR<br/>LCG 0, BS = 0"] --> S["RLC UM PDU<br/>77 bytes, voice"] --> P["Padding<br/>435 bytes"]
Frame 985, 517 bytes. Three subheaders (4 bytes), then the Short BSR body (1 byte), the voice SDU (77 bytes), and padding (435 bytes). The last subheader has no length: padding runs to the end.

Control elements always come before SDUs, in both directions. No PDU of UE 70's in the whole capture breaks the rule. (5G NR differs: its uplink puts control elements after the SDUs, as the MAC-NR page shows.)

The conversation we're following

💡 Where this diagram comes from. VisualEther, the tool that decoded this capture and drew the diagram, splits a trace into per-protocol sessions. This is the one it keys mac-ue::70: every MAC PDU addressed to or sent by C-RNTI 70.

Over the whole capture that session holds about 6,200 arrows, so the diagram shows a window: frames 1–40 (random access, the attach, and the first SIP traffic), 846–857 (call 1's voice bearer is added), 985–1012 (the end of a talk spurt), and the uplink of 1024–1048 (silence). Frame numbers are the original capture's.

Two notes on reading it:

For the whole capture, UE 70's MAC traffic adds up to this:

UplinkDownlink
MAC PDUs8371,000, plus the RAR
Control elements612 Short BSRs, 212 Long BSRs, 445 PHRs1 Contention Resolution
Padding322,978 of 491,777 bytes (66%)13,693 of 294,107 bytes (5%)

Keep the last row in mind. The rules are the same in both directions; the information isn't.

What the log can't show

This is srsRAN's eNB writing its own MAC PDUs to a file. It records what the eNB sent and what it decoded, and nothing below that:

Random access: frames 1 to 3

sequenceDiagram accTitle: LTE contention-based random access for UE 70 accDescr: The UE sends preamble 36 on PRACH, which is not in the log. Frame 1, SFN 421 subframe 6, the eNB sends the Random Access Response on RA-RNTI 2 with Temporary C-RNTI 70 and timing advance 0. Frame 2, SFN 422 subframe 2, the UE sends Msg3, an RRC Connection Request on CCCH. Frame 3, SFN 422 subframe 8, the eNB sends Msg4, the Contention Resolution Identity echoing Msg3 together with the RRC Connection Setup. participant UE participant eNB UE-->>eNB: Msg1 · preamble 36 (PRACH, not in the log) eNB->>UE: Msg2 · Random Access Response, RA-RNTI 2, Temp C-RNTI 70, TA 0 Note over UE,eNB: Frame 1 · SFN 421, subframe 6 UE->>eNB: Msg3 · RRC Connection Request on CCCH, LCID 0 Note over UE,eNB: Frame 2 · SFN 422, subframe 2 eNB->>UE: Msg4 · Contention Resolution Identity + RRC Connection Setup Note over UE,eNB: Frame 3 · SFN 422, subframe 8
Random access as the capture shows it. Msg1 is a physical-layer preamble with no MAC PDU, so the log starts at Msg2.

Frame 1, Msg2. The RAR goes to RA-RNTI 2, an address computed from when the preamble was sent: 1 + t_id + 10 × f_id (TS 36.321 §5.1.4), so the preamble went in subframe 1. It answers preamble 36 with a timing advance of 0, a grant for Msg3, and Temporary C-RNTI 70.

Frame 2, Msg3. LCID 0, CCCH, the one logical channel a UE may use before it has a connection. The SDU is the 6-byte RRC Connection Request with randomValue 9a1ba5de5a, in a 7-byte grant. It goes out six subframes after the RAR, the earliest TS 36.213 §6.1.1 allows. Nothing here singles UE 70 out yet: another UE that picked preamble 36 at the same moment would get the same grant and transmit on top of it.

Frame 3, Msg4. The UE Contention Resolution Identity control element (LCID 28) carries 59a1ba5de5a6, the 48-bit CCCH SDU the eNB decoded from Msg3, sent straight back. The UE compares it with what it sent. On a match it has won, and its Temporary C-RNTI becomes its C-RNTI (TS 36.321 §5.1.5). A UE whose Msg3 lost the collision sees someone else's bytes and starts again.

The same 32-byte block carries the 20-byte RRC Connection Setup on LCID 0 and 2 bytes of padding. Contention resolution belongs to MAC, connection setup to RRC, and MAC delivers both in one transmission. That setup also carries UE 70's entire MAC configuration. What frame 3 told the scheduler compares it with what follows.

The first grants: one every 20 ms

Frame 4 is the first scheduled uplink, at SFN 426 subframe 8. Its 533-byte grant holds four subheaders: a Short BSR (LCID 29), a PHR (LCID 26), a 138-byte SDU on LCID 1 (SRB1, carrying the RRC Connection Setup Complete and the NAS Attach Request), and 387 bytes of padding.

Look at the subframes of the uplink blocks that follow: 430/8, 434/8, 452/8, 456/8, 460/8, 464/8. Each is subframe 8 of an even-numbered frame. Frame 3 set sr-ConfigIndex 15, which puts one SR opportunity every 20 ms, in subframe 0 of even frames (TS 36.213 Table 10.1.5-1). In FDD, an uplink grant applies four subframes after it is sent (TS 36.213 §8.0). Put together:

sequenceDiagram accTitle: Scheduling request to uplink transmission, as inferred from the timing accDescr: In subframe 0 of an even frame, the UE sends a scheduling request on PUCCH, not in the log. In subframe 4, the eNB sends an uplink grant on PDCCH, not in the log. In subframe 8, the UE sends its transport block on PUSCH, which is logged. participant UE participant eNB UE-->>eNB: Scheduling Request on PUCCH (not in the log) Note over UE,eNB: Subframe 0 of an even frame eNB-->>UE: Uplink grant, DCI format 0 on PDCCH (not in the log) Note over UE,eNB: Subframe 4 UE->>eNB: Transport block on PUSCH (logged) Note over UE,eNB: Subframe 8
The 8 ms cycle the uplink timing fits. Only the last step is in the log. The SR and the grant are inferred from sr-ConfigIndex 15 and the FDD grant timing.

The pattern holds across the capture: 551 of UE 70's 836 uplink blocks after Msg3 land on that grid. The rest are extra grants off the grid, like the ones in the next section. The SR itself is a guess from the timing, though a well-supported one. TS 36.321 §5.4.5 says what triggers it: data arriving in an empty buffer triggers a regular BSR, and a regular BSR with no grant in hand triggers an SR.

The first BSR reports nothing. LCG 0, index 0, which Table 6.1.3.1-1 defines as BS = 0. A BSR describes what is left after the current block is built, and the Setup Complete went in the same block. Most BSRs in this capture read zero for the same reason.

The first PHR reads index 56, 33 <= PH < 34 dB: plenty of margin. That number falls one step at a time, and Power headroom below zero follows it.

The downlink between these grants is small and tight: an SRB1 Status PDU or a NAS message in a 7- to 55-byte block, with 2 to 7 bytes of padding.

A backlog: Short BSR, then Long

Frame 20, SFN 464 subframe 8. The UE Capability Information is a 2,017-byte PDCP PDU, too big for one grant. The first segment fills the block exactly (no padding), and the Short BSR asks for the rest: LCG 0, index 33, 1326 < BS <= 1552 bytes.

Frames 21 and 22. The eNB answers off the 20 ms grid with two grants in consecutive subframes: 1,335 bytes at 465/7 and 233 bytes at 465/8. That is 1,568 bytes in total, just over the reported range's top end of 1,552. Frame 21 is one SDU filling the whole block; frame 22 carries the last 163-byte segment, a PHR, and a Long BSR.

Frame 22's BSR teaches how to read BSR formats:

FormatSizeWhen TS 36.321 §5.4.5 uses it
Short BSR1 byte: LCG ID + 6-bit indexa regular or periodic BSR when at most one LCG has data
Long BSR3 bytes: four 6-bit indexes, LCG 0–3a regular or periodic BSR when more than one LCG has data; a padding BSR whenever the padding has room for it
Truncated BSR1 bytea padding BSR with room for a Short but not a Long, when more than one LCG has data

A regular BSR fires when new data arrives; a periodic BSR, when periodicBSR-Timer (sf20 here) expires; a padding BSR, when the padding has room for one. Regular and periodic BSRs take precedence over a padding BSR.

Frame 22's Long BSR reports all four groups at zero. A regular or periodic BSR with no data anywhere would be Short, so this one must be a padding BSR: the block had 60 bytes of padding, room enough for a Long BSR. The same reasoning covers most of the capture's 212 Long BSRs: 184 of them report zero in every group.

Frames 25 and 26. Seven and eight subframes later, the eNB issues the same pair of grants again: 1,335 and 233 bytes. The UE has nothing to send. These are new transmissions, not HARQ retransmissions: a retransmission repeats the same bytes, and these carry a zero Long BSR and 1,558 bytes of padding between them. The log doesn't say why the eNB granted twice. One possibility is that it scheduled the second pair before it had processed frame 22's zero report.

It happens again at frame 847. Its Short BSR reports LCG 2 at index 33, the SIP PRACK waiting on DRB 2. Frames 851 and 852 get 1,335 and 233 bytes and finish the PRACK; frame 852's padding BSR reads zero; and frames 856 and 857 get 1,335 and 501 bytes more, filled with nothing but a zero Long BSR and padding. A non-zero BSR drew two grant pairs, and the second carried only padding.

Frame 40 carries the one padding BSR in the window with something in it: a Long BSR with LCG 2 at index 22, 234 < BS <= 274 bytes, in a block that also holds 341 bytes of padding. The eNB's log can't show why the UE padded rather than sending that data. The next uplink block, frame 42, carries a 267-byte DRB 2 SDU, inside the reported range.

Logical channel groups

A BSR counts groups, so a bearer's group decides what the eNB can tell apart. RRC assigns them as each bearer is created:

BearerLCIDPriorityLCGConfigured in
SRB1110frame 3 (default)
SRB2230frame 24 (default)
DRB 1, internet3113frame 24
DRB 2, IMS signaling4112frame 32
DRB 3, call-1 voice521frame 846

The SRB values are TS 36.331's defaults (§9.2.1.1); the DRB values are explicit in each reconfiguration, all with prioritisedBitRate infinity. With each kind of traffic in its own group, a BSR tells the eNB what kind of data is waiting as well as how much. Frame 39 shows it: the first BSR naming LCG 2, index 32 (1132 < BS <= 1326 bytes), as the SIP REGISTER waits on DRB 2.

Multiplexing in one TTI

A transport block takes whatever is ready in that TTI, from any logical channel. Logical channel prioritization fills a grant highest priority first (TS 36.321 §5.4.3.1), and with every prioritisedBitRate at infinity that is plain priority order. The SDUs in these blocks appear in that order.

Frame 847 is the busiest uplink block in the window, seven subheaders in 533 bytes and no padding:

SubheaderBytesContent
LCID 29 Short BSR1LCG 2, 1326 < BS <= 1552
LCID 26 PHR1index 20, -3 <= PH < -2 dB
LCID 1 SRB12RLC Status PDU
LCID 1 SRB19RRC Connection Reconfiguration Complete for DRB 3
LCID 2 SRB219NAS Activate Dedicated EPS Bearer Context Accept
LCID 4 DRB 22RLC Status PDU
LCID 4 DRB 2488two TCP ACKs and the first 327 bytes of the PRACK

Three logical channels in priority order, five SDUs and two control elements in one 1 ms transmission. The RLC page follows the PRACK across RLC SN 26 to 28.

Frame 991: voice and the SIP bearer. A 77-byte voice SDU on LCID 5, then a 2-byte DRB 2 Status PDU on LCID 4. The IMS bearer's acknowledgment rides in the voice frame's grant instead of waiting for a grant of its own.

Frame 1024: voice and the internet. A 51-byte comfort-noise SDU on LCID 5, then 136 bytes on LCID 3 carrying two TCP packets to port 443. Priority 2 goes first, priority 11 second.

Voice and silence

Call 1's voice bearer, DRB 3 on LCID 5, carries one AMR-WB frame per RTP packet. The uplink in the window:

FramesSFN / subframeLCID 5 SDUOther SDUsPHR
985–1000928/8 to 940/8, every 20 msspeech, 77 bytesDRB 2 status in 991989, 996
1004942/8SID_FIRST, 51 bytes—yes
1012948/8SID_UPDATE, 51 bytes—yes
1024964/8SID_UPDATEDRB 1, 136 bytesyes
1029970/8—DRB 1, 2 + 56 bytesyes
1033, 1037, 1041980/8, 996/8, 1012/8SID_UPDATE—yes
10431014/8—DRB 1, 136 bytesno
10481020/8—DRB 1, 2 + 131 bytesyes

During speech the UE has a frame every 20 ms and gets a grant every 20 ms. When AMR-WB silence suppression starts (TS 26.193), the grants follow the codec: SID_FIRST, a SID_UPDATE 60 ms later, then one every 160 ms. Each SID_UPDATE costs a grant of about 520 bytes to carry 51. The RLC page times the codec frames themselves.

The BSR never moves. All 38 of UE 70's uplink blocks during call 1 (frames 985–1140) sit on the 20 ms grid and carry a Short BSR of zero. A voice frame arrives, the UE gets a grant, the frame fits, and nothing is left over. This call never builds a backlog.

The PHR follows its timer. periodicPHR-Timer sf50 triggers a report 50 ms after the last one, and the report goes out in the next grant (TS 36.321 §5.4.6). During speech, grants come every 20 ms, so a PHR appears every third grant: 60 ms apart (989, 996, 1004). During silence, grants are 160 ms apart, so every grant carries one. Frame 1043, 20 ms after frame 1041, has none. The timer shows most clearly in the attach: frame 21 is 49 subframes after the previous PHR and has none; frame 22, at 50, has one.

Downlink voice comes from UE 71 through the media relay: 105-byte speech SDUs at 23.85 kbit/s, mostly in subframe 5 of odd-numbered frames, each block padded by 5 bytes. Call 1's 45 downlink blocks hold 262 bytes of padding in all; its 38 uplink blocks hold 17,333.

Power headroom below zero

Power headroom is the gap between the UE's maximum transmit power and the power its current grant needs. TS 36.213 §5.1.1.2 computes the needed power from the number of resource blocks granted, the path loss, and the accumulated closed-loop power-control commands. Positive headroom means the eNB could grant more; negative means the UE is already at maximum power and can't reach the target for this grant.

UE 70's reports fall almost one step per report: 56, 55, 54, 53 in frames 4 to 17 (33 <= PH < 34 dB down to 30 <= PH < 31 dB), 48 by frame 36, 20 by frame 847 (-3 <= PH < -2 dB). During call 1 they sit at index 13 to 18: -10 to -4 dB.

The log can't say which input moved. The power-control commands ride on PDCCH, and the grant's resource-block count isn't logged either. Frame 3 sets accumulationEnabled true, and a steady one-step fall is what a run of accumulated "power up" commands would produce. That reading fits, but the log can't confirm it.

What frame 3 told the scheduler

Frame 3's mac-MainConfig is the only MAC configuration UE 70 ever receives: no later reconfiguration carries one.

Configured in frame 3What the capture shows
sr-ConfigIndex 15: SR every 20 ms, offset 0551 of 836 uplink blocks in subframe 8 of an even frame, the timing an SR in subframe 0 would produce
periodicBSR-Timer sf20a BSR in almost every grant; with grants every 20 ms, a periodic trigger can't be told apart from a regular one
retxBSR-Timer sf320not observable: it only matters when a BSR goes unanswered
periodicPHR-Timer sf50, prohibitPHR-Timer sf0, dl-PathlossChange dB3no two PHRs in the window closer than 50 ms; frames 21 and 22 straddle the timer to the subframe
maxHARQ-Tx n4not observable: the log has no HARQ fields
timeAlignmentTimerDedicated infinityno Timing Advance Command for UE 70 in the whole capture; the RAR's timing advance was 0
no drx-Configno DRX; the UE listens all the time

Padding: read it, don't over-read it

Two-thirds of UE 70's uplink bytes are padding, against 5% of its downlink, on the same link under the same rules. The difference is information. The eNB builds a downlink block from data it already holds, so it can size the block to fit. An uplink grant is sized before the eNB knows what the UE will put in it: the SR is one bit, and the BSR describes the moment the last block was built. MAC can't send a shorter block than granted, so whatever is left becomes padding.

So read padding as a measure of how far the grant overshot, not as something the UE chose. Three things not to read into it:

Takeaways

  1. Contention resolution is an echo. The eNB sends the UE's own Msg3 bytes back; the UE that recognizes them keeps its Temporary C-RNTI.
  2. The LCID tables are per direction. 29 is a Short BSR going up and a Timing Advance Command coming down; 28 is a Truncated BSR going up and Contention Resolution coming down.
  3. A BSR reports leftovers, and its format is a clue. Most BSRs read zero because the data went in the same block. A Long BSR with every group at zero can only be a padding BSR.
  4. One MAC entity carries every bearer. Frame 847 holds three logical channels and two control elements; frames 991 and 1024 put voice in the same TTI as SIP feedback and internet traffic.
  5. Call 1 never builds an uplink backlog. Every uplink block of call 1 follows the 20 ms SR grid and reports an empty buffer, every 20 ms in speech and every 160 ms in silence.
  6. Know what an eNB MAC log can't show. Preambles, SRs, grants, power control, and HARQ are all below it. Time by SFN and subframe, not by timestamp.

Where this sits in the stack