PDCP in the protocol stack
PDCP sits above RLC. For SRBs, PDCP receives RRC messages from the RRC layer and encrypts + integrity-protects them before handing to RLC. For DRBs, PDCP receives IP packets from SDAP and ciphers them before handing to RLC.
A critical difference from LTE: in 5G NR, PDCP handles dual connectivity and split bearers — the same PDCP entity can receive data from both a master gNB and a secondary gNB and reorder them before delivering to RLC.
Ciphering
PDCP ciphers each PDU using a keystream generated by the NEA algorithm. The keystream depends on the PDCP COUNT (SN + HFN), bearer identity, direction, and the session key K_UPenc (for DRBs) or K_RRCenc (for SRBs).
// Inputs to NEA2 (AES-CTR, TS 33.501): COUNT = 0x000004D2 ← SN=1234, HFN=0 BEARER = 0x02 ← DRB1 bearer ID DIRECTION = 0 ← downlink LENGTH = 11,968 ← bits to cipher (1,496 bytes) KEY = K_UPenc ← 128-bit key derived by AUSF/AMF // Generate keystream via AES-CTR: keystream = NEA2(COUNT, BEARER, DIRECTION, LENGTH, K_UPenc) = 0xA3F2... (1,496 bytes of pseudorandom keystream) // Cipher the data: ciphered_data = plaintext_IP_packet XOR keystream // At UE receiver (reverse): plaintext = ciphered_data XOR NEA2(same inputs) // XOR is its own inverse — identical operation
Integrity protection
Integrity protection applies to SRBs only (RRC messages) — not to DRBs (user data). It adds a 32-bit MAC-I (Message Authentication Code for Integrity) to each PDU, allowing the receiver to verify the message has not been tampered with.
// MAC-I computation using NIA2 (AES-CMAC): MAC-I = NIA2(COUNT, BEARER, DIRECTION, K_RRCint, Message) = 0x7A3F9C12 (32-bit authentication tag) // PDCP PDU for SRB1: [PDCP Header: SN=47] [Ciphered RRC message] [MAC-I: 0x7A3F9C12] // At receiver: Recompute: MAC-I' = NIA2(same inputs) Check: MAC-I' == received MAC-I → PASS ✓ If fail: discard PDU, report integrity failure to RRC
Header compression (ROHC)
For VoNR (Voice over NR), each voice packet is tiny — perhaps 40 bytes of payload but 40 bytes of IP+UDP+RTP headers. ROHC compresses those 40 bytes down to 1–3 bytes by transmitting the full header only initially, then sending only the delta (what changed) for subsequent packets.
| Phase | Headers sent | Overhead | Description |
|---|---|---|---|
| IR (init) | Full 40 bytes | 40 bytes | First packet — establish context |
| FO (1st order) | Delta only | 4–8 bytes | Changing fields (RTP SN, TS) |
| SO (2nd order) | 1–3 bytes | ~2 bytes | Only RTP SN delta — steady state ← most packets |
PDCP reordering during handover
During handover, the UE switches from one gNB to another. Packets in flight on the old link may arrive after packets on the new link. PDCP sequence numbers allow the receiver to buffer and reorder these packets, ensuring the application layer sees them in sequence despite the radio link discontinuity.