EN-DC SgNB Addition over X2: The Request and Its Acknowledge
Reading two small X2AP-over-SCTP captures that carry the exchange at the heart of 5G Non-Standalone: the SgNB Addition Request, by which an LTE master eNB asks a secondary 5G gNB to stand up an NR data radio bearer for a UE already anchored on LTE — and the Acknowledge with which the gNB replies. Both were decoded and annotated with VisualEther, which turns a Wireshark PCAP into a sequence diagram.
The Request capture — annotated diagrams (the Acknowledge capture's diagrams appear with Act 2 below):
💡 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.
Overview
These are two compact 8-frame captures of the X2 interface — the link between two base stations — carrying the two halves of the one X2AP procedure that makes 5G Non-Standalone work: SgNB Addition. An LTE master eNB (MeNB) that already serves a UE reaches out over X2 to a secondary 5G gNB (SgNB) and asks it to allocate NR radio resources for a new data bearer; the gNB replies with what it can allocate. That is how a 4G operator layers 5G throughput onto an existing LTE anchor without a 5G core.
- Act 1 — the Request: the MeNB's ask — an
SgNBAdditionRequestcarrying the bearer to add, "with DRB-ID". - Act 2 — the Acknowledge: the gNB's admit — an
SgNBAdditionRequestAcknowledgethat mints the SgNB-UE-X2AP-ID, admits the E-RAB, and returns the RRC CG-Config.
A caveat up front, because it changes how you read every value in both traces. These are synthetic captures — message-builder / conformance traces (every endpoint sits on 127.0.0.1, distinguished only by SCTP port), not live inter-node dialogs. Many payloads are placeholders typical of such tools: an all-zero SgNB security key, 0.0.0.0 / TEID-0 GTP endpoints, UE security capabilities that advertise no standard algorithms, an rlc-Mode of "Unknown", and an empty CG-Config. Read them as a faithful demonstration of the message structure of EN-DC bearer addition — which IEs travel, and what they mean — not as a set of realistic network values. Where a field is a placeholder, this walkthrough indicates as much.
One more caveat that keeps us honest: the two captures are not the two ends of one wire. They come from the same message-builder family but are independent traces — the UE identifiers and E-RAB IDs do not match across them (the Request uses MeNB-UE-X2AP-ID 1 / E-RAB 11; the Acknowledge uses MeNB-UE-X2AP-ID 85 / SgNB-UE-X2AP-ID 102 / E-RAB 119). So read Act 2 as what a matching-shape Acknowledge carries, not as the literal reply to the Act 1 request. That is exactly why this procedure needs two captures to show in full: neither trace carries both directions.
Every step is visible in the packets. In either capture's interactive viewer or HTML sequence diagram, click any message to open its parameter details and the complete Wireshark field tree for that frame.
A primer on EN-DC and X2AP
EN-DC (E-UTRA–NR Dual Connectivity) is the dual-connectivity mode behind 5G Non-Standalone, Option 3. The UE keeps its control-plane anchor on an LTE MeNB (master eNB) connected to the 4G EPC, and gains a second, high-throughput user-plane leg on a 5G SgNB (secondary gNB). The two base stations coordinate over the X2 interface.
| Piece | Role in one line | What you'll see in the trace |
|---|---|---|
| MeNB | LTE master — owns the UE and its control plane | Initiates the association (SCTP port 41471 in the Request capture, 44762 in the Acknowledge); sends the X2 Setup |
| SgNB | 5G secondary — adds NR user-plane capacity | Responder on SCTP port 62324; returns the Acknowledge (Act 2) |
| X2AP | The application protocol spoken over X2 | X2 Setup Request, SgNB Addition Request, SgNB Addition Request Acknowledge |
| SCTP | The reliable transport X2AP rides on | INIT / INIT-ACK / COOKIE-ECHO / COOKIE-ACK, then ABORT |
| Split bearer | One bearer using both nodes' lower layers | en-DC-ResourceConfiguration with MCG + SCG resources |
Two ideas do the heavy lifting in both captures:
X2AP rides on SCTP, and SCTP comes up first. Unlike TCP, SCTP opens an association with a four-way handshake and multiplexes independent streams so that non-UE signaling (the X2 Setup) and per-UE signaling (the SgNB Addition) never head-of-line block each other. Nothing at the X2AP layer can happen until that association is established.
The added bearer is a split bearer anchored at the MeNB. The SgNB Addition Request asks the gNB to contribute NR radio resources for a Data Radio Bearer. Still, the request here keeps PDCP at the MeNB (resource-configuration: sgNBPDCPnotpresent) while marking both MCG (LTE) and SCG (NR) lower-layer resources present. That shape — one bearer, PDCP at the master, data split across both nodes' radios — is the classic MCG-anchored split bearer of Option 3. And it carries an explicit DRB-ID, which is what this capture is named for: the MeNB pins the NR bearer's identity rather than leaving the SgNB to choose it.
The flow at a glance
Both captures share the same eight-frame skeleton and differ only in the single X2AP payload at frame 7. Read once, the shape is:
- SCTP association setup (frames 1–4) — the four-way INIT / INIT-ACK / COOKIE-ECHO / COOKIE-ACK handshake that opens the transport.
- X2 Setup (frame 5) — the MeNB introduces itself and its served cell (non-UE-associated). Identical in both captures.
- The X2AP payload (frame 7) — the one frame that differs: the SgNB Addition Request in Act 1, the SgNB Addition Request Acknowledge in Act 2.
- SCTP ABORT (frame 8) — the association is torn down before any graceful close. (Frame 6, in each capture, is the SCTP acknowledgment of frame 5, not an X2AP message.)
So the plan below is: walk the shared skeleton — SCTP, then X2 Setup — once; then look at each frame-7 payload in turn, the Request and then the Acknowledge; and close on the teardown they both share.
Read end-to-end, the two captures trace one procedure — but only the X2 slice of it. Here is the full logical flow, including the UE and the over-the-air (Uu) messages the X2 captures never see: the MeNB requests the NR bearer, the SgNB acknowledges, the MeNB hands the UE the NR configuration, and once the UE completes and accesses the NR cell, the EN-DC leg is live. Each synthetic capture holds only a fragment of this — Act 1's the SgNB Addition Request, Act 2's the Acknowledge — and nothing on the Uu interface at all.
Want the whole EN-DC procedure, not just this X2 slice? This walkthrough zooms in on the two X2AP messages at the center of SgNB Addition. For the complete Non-Standalone signaling — the UE's registration for dual connectivity, the bearer move onto the gNB, and the EPC's part in it — see the full 5G-NR Non-Standalone access call flows.
This is a picture of the X2 topology the messages act on — a UE anchored at the MeNB, with X2 reaching the SgNB that will add the NR leg:
Underneath the X2AP messages, the SCTP association runs its own lifecycle — and in both captures it never reaches a graceful close; it is aborted:
Now the same story, frame by frame — starting with the skeleton both captures share.
Bringing up the transport — SCTP (frames 1–4)
Frames 1–4 — the SCTP four-way handshake. X2AP is carried over SCTP, not TCP, so before any application messages are exchanged, the two nodes establish an association. The MeNB's INIT (frame 1) offers 10 outbound streams; the SgNB's INIT-ACK (frame 2) returns its own parameters plus a state cookie and commits no state yet — that cookie carries the association state, so the responder holds nothing until the echo returns, a feature of SCTP's built-in anti-DoS design. The MeNB's COOKIE-ECHO (frame 3) proves the round-trip, and the SgNB's COOKIE-ACK (frame 4) opens the association in both directions.
Those multiple streams matter for what follows: X2AP deliberately keeps non-UE-associated signaling (the X2 Setup) on a separate stream from UE-associated procedures (the SgNB Addition). Hence, a stall on one never blocks the other. Throughout this loopback capture, the 41471 ↔ 62324 port pair is the only difference between MeNB and SgNB. (The Acknowledge capture of Act 2 runs the same handshake on 44762 ↔ 62324 — same responder port, different initiator port, one small confirmation that it is a separate trace.)
Bringing up the X2 interface — X2 Setup (frame 5)
Frame 5 — X2 Setup Request (non-UE-associated). Before any per-UE work, the MeNB introduces itself so the peer knows who it is and which cells it serves. The decoded contents:
| IE | Value | Meaning |
|---|---|---|
| Global eNB-ID | 1 | macro eNB-ID (20-bit), decimal 1 |
| Served cells | 1 | one E-UTRA cell advertised |
| PCI | 6 | physical cell ID |
| TAC | 0 | tracking area code |
| Broadcast PLMNs | 001-01, 001-02, 001-03 | the three PLMNs the cell broadcasts |
| UL/DL EARFCN | 3350 | carrier frequency (same up and down in the test data) |
Both captures advertise the same served-cell configuration — the same builder produced them — so the X2 Setup reads the same whether the following frame-7 payload is the Request or the Acknowledge.
Normally the peer answers with an X2 Setup Response, and only then does UE-associated signaling begin. Here the MeNB does not wait — it fires its frame-7 payload immediately, and no response ever arrives. That "send everything, don't wait" pattern is one more tell that these are message-builder traces rather than a real gNB dialog. (Frame 6, in each capture, is the SCTP acknowledgment of frame 5, not an X2AP message.)
Act 1 — The Request: adding the 5G bearer (frame 7)
Frame 7 — SgNB Addition Request. This is the message the whole capture exists to show: X2AP procedure id-sgNBAdditionPreparation (27). The MeNB, the LTE anchor that owns the UE, asks the secondary gNB to allocate NR radio resources so the UE can run in dual connectivity. The MeNB owns the UE-association here — the identifier is the MeNB-UE-X2AP-ID = 1; the gNB would mint its own SgNB-UE-X2AP-ID in the Acknowledge that never comes.
The bearer being added, decoded from the E-RABs-ToBeAdded list (exactly one item):
- E-RAB-ID 11, mapped to DRB-ID 1 — the explicit Data Radio Bearer identity this capture is named for. Carrying the DRB-ID in the request lets the MeNB pin the NR DRB identity rather than leaving it to the SgNB.
en-DC-ResourceConfiguration—pDCPatSgNB,mCGresources, andsCGresourcesare all present, i.e. this bearer draws on both Master and Secondary Cell Group lower-layer resources (a split-bearer shape).resource-configuration: sgNBPDCPnotpresent— the PDCP anchor stays at the MeNB; the SgNB contributes NR RLC/MAC/PHY only. So this is an MCG-anchored split bearer, not an SCG bearer with SgNB-terminated PDCP.- Requested SCG E-RAB QoS — QCI 16, ARP priority = highest (1), shall-not-trigger-pre-emption, not-pre-emptable. (QCI 16 is not one of the standardized LTE QCIs — read it as a test value.)
meNB-UL-GTP-TEIDatPDCP— the MeNB's uplink GTP-U endpoint for the split bearer, here0.0.0.0/ TEID0x00000000(placeholder), withrlc-Mode"Unknown". Real values would point the SgNB's uplink X2-U traffic back at the MeNB's PDCP.
Security-context IEs are present but carry placeholder patterns: the SgNBSecurityKey (S-KgNB) is all zeros (256-bit), and the NR UE security capabilities advertise no standard algorithms (the 128-NEA and 128-NIA bits all decode as Not supported). An opaque MeNBtoSgNBContainer — the RRC CG-ConfigInfo — is included as a short stub. In a live add, the gNB would use S-KgNB and these capabilities to configure NR security and reply with a SgNB Addition Request Acknowledge carrying the SCG RRCReconfiguration. That reply is the whole of Act 2 — and watch the container's direction: here the MeNB sends the MeNB→SgNB container, an RRC CG-ConfigInfo, to the SgNB; in Act 2 the SgNB sends the SgNB→MeNB container back, an RRC CG-Config — same procedure, two different RRC containers, one each way.
Here is that request as its fully decoded packet — click any layer to drill in (x2ap is open to the message; expand E-RABs-ToBeAdded and the security IEs to see the placeholders discussed above):
frame : Frame 7: Packet, 196 bytes on wire (1568 bits), 196 bytes captured (1568 bits) on interface any, id 0
Interface id : 0 (any)
sll : Linux cooked capture v1
ip : Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Differentiated Services Field : 0x02 (DSCP: CS0, ECN: ECT(0))
010. .... = Flags : 0x2, Don't fragment
sctp : Stream Control Transmission Protocol, Src Port: 41471 (41471), Dst Port: 62324 (62324)
DATA chunk (ordered, complete segment, TSN : 1, SID: 0, SSN: 1, PPID: 0, payload length: 129 bytes)
Chunk type : DATA (0)
Chunk flags : 0x03
x2ap : EUTRAN X2 Application Protocol (X2AP)
X2AP-PDU : initiatingMessage (0)
initiatingMessage
value
SgNBAdditionRequest
protocolIEs : 6 items
Item 0 : id-MeNB-UE-X2AP-ID
ProtocolIE-Field
value
Item 1 : id-NRUESecurityCapabilities
ProtocolIE-Field
value
NRUESecurityCapabilities
nRencryptionAlgorithms : 0001 [bit length 16, 0000 0000 0000 0001 decimal value 1]
nRintegrityProtectionAlgorithms : 0002 [bit length 16, 0000 0000 0000 0010 decimal value 2]
Item 2 : id-SgNBSecurityKey
ProtocolIE-Field
value
Item 3 : id-SgNBUEAggregateMaximumBitRate
ProtocolIE-Field
value
UEAggregateMaximumBitRate
Item 4 : id-E-RABs-ToBeAdded-SgNBAddReqList
ProtocolIE-Field
value
E-RABs-ToBeAdded-SgNBAddReqList : 1 item
Item 0 : id-E-RABs-ToBeAdded-SgNBAddReq-Item
ProtocolIE-Single-Container
value
E-RABs-ToBeAdded-SgNBAddReq-Item
en-DC-ResourceConfiguration
resource-configuration : sgNBPDCPnotpresent (1)
sgNBPDCPnotpresent
requested-SCG-E-RAB-Level-QoS-Parameters
allocationAndRetentionPriority
meNB-UL-GTP-TEIDatPDCP
transportLayerAddress : 00000000 [bit length 32, 0000 0000 0000 0000 0000 0000 0000 0000 decimal value 0]
Item 5 : id-MeNBtoSgNBContainer
ProtocolIE-Field
value
MeNBtoSgNBContainer : f0f1f20000000000000000000000000000000000000000000000000000000000
CG-ConfigInfo
criticalExtensions : criticalExtensionsFuture (1)
Act 2 — The Acknowledge: the SgNB's reply, carrying CG-Config (frame 7)
Everything to here — SCTP, X2 Setup, the frame-8 ABORT — was the shared skeleton, read from the Request capture. Act 2 is a second capture (Wireshark issue #14940), built the same way, whose frame 7 carries the message the Request capture never received: the SgNB Addition Request Acknowledge. It has its own annotated diagrams:
Frame 7 — SgNB Addition Request Acknowledge. Same X2AP procedure as Act 1 — id-sgNBAdditionPreparation (27) — but now a successfulOutcome. Where the Request carried the MeNB's ask, this carries the SgNB's admit: the SCG resources the gNB allocated, and the RRC container the MeNB will forward to the UE. The decoded contents:
| IE | Value | Meaning |
|---|---|---|
| MeNB-UE-X2AP-ID | 85 | the MeNB's UE-association ID, echoed back |
| SgNB-UE-X2AP-ID | 102 | the gNB now mints its own UE ID — the half the Request lacked |
| E-RAB-ID (admitted) | 11 → 119 | one E-RAB admitted, in E-RABs-Admitted-ToBeAdded-SgNBAddReqAckList |
en-DC-ResourceConfiguration | pDCPatSgNB, mCGresources, sCGresources all present | the split-bearer shape, echoed from the request |
resource-configuration | sgNBPDCPnotpresent | PDCP stays at the MeNB — an MCG-anchored split bearer |
sgNB-DL-GTP-TEIDatSCG | 0.0.0.0 / TEID 0x00000000 | the SgNB's downlink X2-U endpoint for the SCG leg (placeholder) |
Two things make this the more interesting half of the procedure:
The UE-association is now complete. The Request carried only a MeNB-UE-X2AP-ID; the Acknowledge returns that plus the gNB's own SgNB-UE-X2AP-ID = 102. That pair — one ID minted by each node — is the handle both sides use for every later X2AP message about this UE. (As flagged in the Overview, these values — 85 / 102 / 119 — don't match the Request capture's 1 / 11, because the two captures are independent builder traces; read this as the shape of the reply, not the literal answer to Act 1's request.)
The SgNBtoMeNBContainer carries an RRC CG-Config. This is the field the capture is really about. The container (IE id-211) is a short stub that Wireshark dissects as nr-rrc CG-Config → criticalExtensions: c1: cg-Config, with every optional bit false — no scg-CellGroupConfig, no scg-RB-Config, no configRestrictModReq. So it is a well-formed but empty CG-Config: the right container, carrying no actual SCG cell-group configuration (a placeholder, as in these traces). In a live add, this is where the SCG RRCReconfiguration would ride back to the MeNB for relay to the UE, thereby standing up the NR leg.
The direction of that container is the crux of Wireshark issue #14940, which this capture comes from: the SgNB→MeNB container must decode as CG-Config (TS 38.331), not the CG-ConfigInfo that travels the other way in Act 1's MeNBtoSgNBContainer: one procedure, two RRC containers — CG-ConfigInfo out, CG-Config back.
One last honest note about the diagram. Read the on-wire direction carefully: this loopback builder emits every application PDU from the initiator socket (44762), so on the wire the Acknowledge travels toward the SgNB — the same direction as the X2 Setup. Semantically it is the SgNB's reply to the MeNB as shown in the inline diagram above. Read the hosted capture diagram for the message's content, not its arrow direction — the same "structure, not values" discipline the rest of this trace demands.
And the Acknowledge as its full decoded packet — expand the x2ap subtree to find the SgNB-UE-X2AP-ID, the admitted E-RAB, and the SgNBtoMeNBContainer carrying the CG-Config:
frame : Frame 7: Packet, 124 bytes on wire (992 bits), 124 bytes captured (992 bits) on interface any, id 0
Interface id : 0 (any)
sll : Linux cooked capture v1
ip : Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Differentiated Services Field : 0x02 (DSCP: CS0, ECN: ECT(0))
010. .... = Flags : 0x2, Don't fragment
sctp : Stream Control Transmission Protocol, Src Port: 44762 (44762), Dst Port: 62324 (62324)
DATA chunk (ordered, complete segment, TSN : 1, SID: 0, SSN: 1, PPID: 0, payload length: 57 bytes)
Chunk type : DATA (0)
Chunk flags : 0x03
x2ap : EUTRAN X2 Application Protocol (X2AP)
X2AP-PDU : successfulOutcome (1)
successfulOutcome
value
SgNBAdditionRequestAcknowledge
protocolIEs : 4 items
Item 0 : id-MeNB-UE-X2AP-ID
ProtocolIE-Field
value
Item 1 : id-SgNB-UE-X2AP-ID
ProtocolIE-Field
value
Item 2 : id-E-RABs-Admitted-ToBeAdded-SgNBAddReqAckList
ProtocolIE-Field
value
E-RABs-Admitted-ToBeAdded-SgNBAddReqAckList : 1 item
Item 0 : id-E-RABs-Admitted-ToBeAdded-SgNBAddReqAck-Item
ProtocolIE-Single-Container
value
E-RABs-Admitted-ToBeAdded-SgNBAddReqAck-Item
en-DC-ResourceConfiguration
resource-configuration : sgNBPDCPnotpresent (1)
sgNBPDCPnotpresent
sgNB-DL-GTP-TEIDatSCG
transportLayerAddress : 00000000 [bit length 32, 0000 0000 0000 0000 0000 0000 0000 0000 decimal value 0]
Item 3 : id-SgNBtoMeNBContainer
ProtocolIE-Field
value
SgNBtoMeNBContainer : 00100ea084c400188000
CG-Config
criticalExtensions : c1 (0)
c1 : cg-Config (0)
cg-Config
candidateServingFreqListNR : 1 item
Item 0
The teardown — an SCTP ABORT, not a verdict (frame 8)
Both captures end the same way — not with an X2AP follow-up or a graceful SCTP SHUTDOWN, but with an ABORT:
Frame 8 — SCTP ABORT. In both captures, the SgNB-side endpoint (port 62324) sends an SCTP ABORT with cause "User initiated ABORT" (0x000c). Read this carefully: it is a graceful, application-driven socket teardown — not an X2AP SgNBAdditionRequestReject, and not a protocol error. The test tool closed the association after emitting its PDUs.
Consequently, each capture is incomplete::no-close at X2AP and failure::aborted at SCTP — even the Act 2 capture, whose frame 7 is itself a successful outcome. It looks like a failure; it is really just the capture ending. And it is one more reason the procedure takes two captures to show in full: neither one carries a graceful, two-directional exchange.
Reading a synthetic capture
The most useful skill these traces teach is not about EN-DC at all — it is how to tell structure from values. A message-builder capture like these is authored to exercise the encoding of a procedure. Every mandatory IE is present and correctly typed, so the message decodes cleanly, and you can study exactly which parameters an SgNB Addition Request and its Acknowledge carry. But the contents are filler — zero keys, 0.0.0.0 endpoints, "Unknown" modes, capability bitmaps with nothing set, an empty CG-Config.
Three habits keep you honest when you meet one on a real analysis:
- Distinguish a transport event from an application verdict. The frame-8 ABORT ends the association, but it says nothing about whether the SgNB accepted the bearer. Act 2 makes the point vividly: its frame 7 is a successful Acknowledge, yet the association still aborts a frame later — the SCTP teardown and the X2AP outcome are independent facts at different layers. A real rejection, likewise, would be an X2AP
SgNBAdditionRequestRejectwith a cause, not an ABORT. - Double-check the values against the spec. An all-zero security key, a
0.0.0.0GTP endpoint, an empty CG-Config, or a QCI that isn't in the standard tables are the fingerprints of test data, not of a network you should be troubleshooting. - Don't over-read on-wire direction in a builder trace. This tool emits every PDU from the initiator socket, so Act 2's Acknowledge travels toward the SgNB even though it is semantically the SgNB's reply. On a synthetic capture, trust the message type and its IEs over the arrow's direction.
📨 Have a complete EN-DC capture? Both traces here are synthetic message-builder samples — a full, real-world Non-Standalone flow (UE registration for dual connectivity, then SgNB Addition and the bearer moving onto the gNB) isn't publicly available anywhere we could find. If you have one you can share, send it to support@eventhelix.com, and we'll turn it into an annotated walkthrough like this one — and credit the source of the flow.
Takeaways
- EN-DC grafts 5G onto LTE over X2, in two moves. The UE remains anchored to the LTE MeNB; the MeNB requests an NR leg over X2 (Act 1), and the SgNB acknowledges the admission (Act 2). Those two X2AP messages are the whole of SgNB Addition.
- SCTP first, X2AP second. No X2AP message can flow until the four-way SCTP handshake establishes the association, and its multiple streams keep non-UE and per-UE signaling from blocking each other.
- The bearer is an MCG-anchored split bearer. PDCP remains at the MeNB (
sgNBPDCPnotpresent), while both MCG and SCG resources are marked as present. The Request pins the NR bearer with an explicit DRB-ID; the Acknowledge echoes the same split-bearer shape back. - The Acknowledge completes the UE association and returns the CG-Config. The gNB mints its own SgNB-UE-X2AP-ID to pair with the MeNB's, admits the E-RAB, and returns the SCG configuration as an RRC CG-Config — the reply container, distinct from the
CG-ConfigInfothe MeNB sent outbound. - An SCTP ABORT is not an X2AP reject. Both associations are torn down at the transport layer — even the one whose frame 7 was a successful Acknowledge. Read the SCTP outcome and the X2AP outcome as independent facts.
- Know structure from values — and it takes two captures to see both directions. These are message-builder traces: trust them for which IEs an SgNB Addition Request and its Acknowledge carry, not for the placeholder contents inside them, and remember the two are independent traces, not two ends of one wire.
Try it on your own capture
Every arrow in this walkthrough was decoded and captioned by VisualEther from a raw Wireshark PCAP — no manual diagramming. Point it at your own 5G, LTE, or IMS trace and read it the same way.