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.
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:
- Random access. It turns an anonymous preamble into a connected UE with its own C-RNTI (Cell Radio Network Temporary Identifier), the 16-bit address the cell uses for one device.
- Multiplexing. It packs SDUs (service data units: the RLC PDUs handed down) from several logical channels, plus its own control elements, into one transport block, each behind a subheader that names its LCID.
- Reporting. The eNB schedules the uplink, but can't see inside the phone. The UE tells it, in control elements: how much data is queued (the Buffer Status Report) and how much transmit power is left (the Power Headroom Report).
- HARQ. It retransmits blocks that fail to decode. The capture can't show this one; see What the log can't show.
Everything MAC does travels in the clear. Ciphering is a PDCP function, and here it is EEA0 anyway.
The fields
| Field | Meaning |
|---|---|
LCID | Logical 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). |
| Subheader | One 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). |
BSR | Buffer 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). |
LCG | Logical Channel Group, 0–3. RRC puts each logical channel in a group; the BSR reports groups, not channels. |
PHR | Power 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). |
SR | Scheduling 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. |
| Padding | LCID 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:
| LCID | Downlink (Table 6.2.1-1) | Uplink (Table 6.2.1-2) | Seen for UE 70 |
|---|---|---|---|
| 0 | CCCH | CCCH | once each way: Msg4 and Msg3 |
| 1–10 | logical channel | logical channel | 1 SRB1, 2 SRB2, 3 DRB 1, 4 DRB 2, 5–10 the six voice bearers |
| 26 | Long DRX Command | Power Headroom Report | 445 PHRs |
| 27 | Activation/Deactivation | C-RNTI | — |
| 28 | UE Contention Resolution Identity | Truncated BSR | 1 Contention Resolution, 0 Truncated BSR |
| 29 | Timing Advance Command | Short BSR | 612 Short BSRs, 0 Timing Advance Commands |
| 30 | DRX Command | Long BSR | 212 Long BSRs |
| 31 | Padding | Padding | both 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:
Frame 985, UE 70's first voice uplink, shows a whole MAC PDU:
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:
- Each control element is drawn twice. Once as its own arrow with its fields (BSR, PHR, RAR, or Contention Resolution), and once in place among the PDU's subheaders. A frame with a BSR, a PHR, one SDU, and padding draws six arrows.
- Frame 1 is in the session by a fallback. The Random Access Response is addressed to RA-RNTI 2, not to C-RNTI 70. The session key falls back to the Temporary C-RNTI the RAR assigns, which is 70.
For the whole capture, UE 70's MAC traffic adds up to this:
| Uplink | Downlink | |
|---|---|---|
| MAC PDUs | 837 | 1,000, plus the RAR |
| Control elements | 612 Short BSRs, 212 Long BSRs, 445 PHRs | 1 Contention Resolution |
| Padding | 322,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:
- No preamble, no SR, no grants. The PRACH preamble, scheduling requests on PUCCH, and grants and power-control commands on PDCCH are physical-layer signals. srsRAN logs the size of the grant with each uplink PDU, nothing more.
- No HARQ. Every PDU carries
CRC Status: OK, and none carries a retransmission count.maxHARQ-Txn4 allows up to four transmissions of each uplink block, but the log can't say how many any block needed, or show one that failed. - Log time isn't air time. The timestamp is when srsRAN wrote the frame. Msg3 and Msg4 are six subframes apart by SFN and subframe, but 2 ms apart by timestamp. This page times everything by SFN (system frame number, 10 ms) and subframe (1 ms).
Random access: frames 1 to 3
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:
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:
| Format | Size | When TS 36.321 §5.4.5 uses it |
|---|---|---|
| Short BSR | 1 byte: LCG ID + 6-bit index | a regular or periodic BSR when at most one LCG has data |
| Long BSR | 3 bytes: four 6-bit indexes, LCG 0–3 | a regular or periodic BSR when more than one LCG has data; a padding BSR whenever the padding has room for it |
| Truncated BSR | 1 byte | a 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:
| Bearer | LCID | Priority | LCG | Configured in |
|---|---|---|---|---|
| SRB1 | 1 | 1 | 0 | frame 3 (default) |
| SRB2 | 2 | 3 | 0 | frame 24 (default) |
| DRB 1, internet | 3 | 11 | 3 | frame 24 |
| DRB 2, IMS signaling | 4 | 11 | 2 | frame 32 |
| DRB 3, call-1 voice | 5 | 2 | 1 | frame 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:
| Subheader | Bytes | Content |
|---|---|---|
LCID 29 Short BSR | 1 | LCG 2, 1326 < BS <= 1552 |
LCID 26 PHR | 1 | index 20, -3 <= PH < -2 dB |
LCID 1 SRB1 | 2 | RLC Status PDU |
LCID 1 SRB1 | 9 | RRC Connection Reconfiguration Complete for DRB 3 |
LCID 2 SRB2 | 19 | NAS Activate Dedicated EPS Bearer Context Accept |
LCID 4 DRB 2 | 2 | RLC Status PDU |
LCID 4 DRB 2 | 488 | two 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:
| Frames | SFN / subframe | LCID 5 SDU | Other SDUs | PHR |
|---|---|---|---|---|
| 985–1000 | 928/8 to 940/8, every 20 ms | speech, 77 bytes | DRB 2 status in 991 | 989, 996 |
| 1004 | 942/8 | SID_FIRST, 51 bytes | — | yes |
| 1012 | 948/8 | SID_UPDATE, 51 bytes | — | yes |
| 1024 | 964/8 | SID_UPDATE | DRB 1, 136 bytes | yes |
| 1029 | 970/8 | — | DRB 1, 2 + 56 bytes | yes |
| 1033, 1037, 1041 | 980/8, 996/8, 1012/8 | SID_UPDATE | — | yes |
| 1043 | 1014/8 | — | DRB 1, 136 bytes | no |
| 1048 | 1020/8 | — | DRB 1, 2 + 131 bytes | yes |
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 3 | What the capture shows |
|---|---|
sr-ConfigIndex 15: SR every 20 ms, offset 0 | 551 of 836 uplink blocks in subframe 8 of an even frame, the timing an SR in subframe 0 would produce |
periodicBSR-Timer sf20 | a BSR in almost every grant; with grants every 20 ms, a periodic trigger can't be told apart from a regular one |
retxBSR-Timer sf320 | not observable: it only matters when a BSR goes unanswered |
periodicPHR-Timer sf50, prohibitPHR-Timer sf0, dl-PathlossChange dB3 | no two PHRs in the window closer than 50 ms; frames 21 and 22 straddle the timer to the subframe |
maxHARQ-Tx n4 | not observable: the log has no HARQ fields |
timeAlignmentTimerDedicated infinity | no Timing Advance Command for UE 70 in the whole capture; the RAR's timing advance was 0 |
no drx-Config | no 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:
- A padding BSR is not a request. Most Long BSRs here exist only because the padding had room; 184 of 212 report zero in every group.
- A full block is not a backlog. Frames 20, 21, 39, and 847 have no padding at all. Read the BSR to know whether data is still waiting.
- Padding at the front is not an error. 27 downlink blocks in the capture begin with one or two padding subheaders. TS 36.321 §6.1.2 adds one or two bytes of padding that way, at the start, rather than as a padding subheader at the end.
Takeaways
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
- An LTE Attach and a VoLTE Call on the Air Interface: the full walkthrough this page is a slice of, with every layer on one timeline.
- RLC-LTE: Acknowledged and Unacknowledged Mode: the layer above. Every
LCID 4andLCID 5SDU on this page is one RLC PDU there. - PDCP-LTE: Sequence Numbers, COUNT, and the MAC-I: two layers up, including frame 1024's voice and internet PDUs side by side.
- LTE-RRC: One Connection, Fourteen Reconfigurations: where
mac-MainConfig, the LCIDs, and the logical channel groups come from. - SIP: IMS Registration and the VoLTE Call: the PRACK, the REGISTER, and the RTP that fill these transport blocks.
- MAC-NR in a Real 5G Capture: the same layer in 5G, with 6-bit LCIDs and control elements after the SDUs on the uplink.