According to TS 38.413:
* AMBR is conditional to PDU Session Resource to setup in the Initial UE
Context Setup procedure
* The UE Aggregate Maximum Bit Rate IE should be sent to the NG-RAN node
if the AMF has not sent it previously. If it is included in the PDU
SESSION RESOURCE SETUP REQUEST message, the NG-RAN node shall store
it in the UE context
* Range is INTEGER [0..4,000,000,000,000]
To this purpose, changes in the commit:
* Init AMBR to out of range value when creating UE context
* Store AMBR in UE context whenever is received
* Assert if not set at the time of Bearer Setup (should be known at that stage)
Extract common code from `fill_drb_to_be_setup_from_e1_resp` and
`rrc_fill_f1_drb_to_setup` into reusable helper functions to reduce
duplication and improve maintainability. This refactoring enables
multi-QoS flow handling per DRB and prepares helpers for upcoming
PDU Session Modify changes.
Impact:
- Enables multi-QoS flow support: `rrc_fill_f1_drb_to_setup` now
collects all QFIs mapped to a DRB instead of only the first one
- Reduces code duplication between E1 response and direct DRB setup
code paths
- Improves maintainability by centralizing F1 DRB setup logic
Major changes:
- Add `fill_f1_drb_info_nr`: fills DRB information IE including QoS
flows from QFI list
- Add `fill_f1_drb_to_be_setup`: creates F1 DRB to setup structure
from RRC DRB, PDU session, and QFI list
- Add `fill_f1_drbs_from_e1`: processes DRBs from E1 response and
extracts QFIs from drb_config->qosFlows
- Refactor `fill_drb_to_be_setup_from_e1_resp` to use
`fill_f1_drbs_from_e1`
- Refactor `rrc_fill_f1_drb_to_setup` to collect all QFIs mapped to
each DRB and use `fill_f1_drb_to_be_setup`
TS 38.413 8.2.3 PDU Session Modify:
> For each PDU session which failed to be modified, the PDU Session Resource Modify
> Unsuccessful Transfer IE shall be included containing the failure cause
> If the NG-RAN node receives a PDU SESSION RESOURCE MODIFY REQUEST message containing
> some PDU Session ID IEs (in the PDU Session Resource Modify Request List IE) that the
> NG-RAN node does not recognize, the NG-RAN node shall report the corresponding invalid
> PDU sessions as failed in the PDU SESSION RESOURCE MODIFY RESPONSE message
> with an appropriate cause value
Changes in the commit:
* add rrc_gNB_ngap_pdusession_mod_failure helper function to handle
abnormal conditions and send NGAP response with (all) failed PDU sessions
* improve error handling: send NGAP response instead of silently returning -1
when UE context lookup fails (unknown RAN UE NGAP ID)
* add AMF UE NGAP ID validation: check stored AMF UE NGAP ID matches request
and send failure response if mismatch (per 3GPP TS 38.413)
* handle unrecognized PDU Session IDs per 3GPP TS 38.413 8.2.3.4: add to
failed list to be sent in the reponse message
* simplify failure path: reuse rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP
instead of manually constructing response message
* remove failed PDU sessions from RRC list in rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP
* remove redundant code and improve code organization
* add bounds checking
* improve function signature
This commit refactors the rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP function
to improve code clarity, fix bugs, and ensure compliance with 3GPP TS 38.413
section 9.2.1.6.
The main improvement is ensuring the PDU Session Resource Modify Response message
is always sent with mandatory IEs, even when there are no PDU sessions to report
in the optional lists.
Key changes:
- Initialize message structure parameters to 0 by leveraging structure
initialization, ensuring clean state
- Replace local counter variables (pdu_sessions_done, pdu_sessions_failed)
with direct access to resp->nb_of_pdusessions and resp->nb_of_pdusessions_failed,
eliminating redundant state tracking and improving code clarity
- Remove conditional message sending: always send the response message
(per 3GPP TS 38.413 9.2.1.6, PDUSessionResourceModifyResponse must always
be sent with mandatory IEs: AMF-UE-NGAP-ID and RAN-UE-NGAP-ID, even when
optional lists are empty)
- Fix duplicate assignment: remove redundant p->pdusession_id assignment
(was assigned twice in the PDU_SESSION_STATUS_DONE case)
- Improve failed PDU session handling: use direct structure assignment
(failed->cause = session->cause) instead of field-by-field copying,
making the code more maintainable
- Remove failed PDU session upon response
- Enhance logging: improve log messages for better debugging and clarity
- Add function documentation comment
Introduce fill_e1_qos_flow_to_setup to translate pdusession_level_qos_parameter_t (NGAP)
into qos_flow_to_setup_t (E1), including ARP and QoS characteristics (dynamic/non-dynamic).
Refactor fill_e1_drb_to_setup to use the new helper for building QoS flows.
* Only include QoS flows whose drb_id matches the target DRB.
* Add DevAssert(drb_ngran.numQosFlow2Setup > 0) to ensure at least one QoS flow is added.
This change centralizes and simplifies QoS mapping logic between NGAP inputs
and E1 DRB configuration. It ensures correctness by associating QoS flows
to the appropriate DRB.
Major changes:
- Extract QoS flow mapping logic into fill_e1_qos_flow_to_setup helper function
- Filter QoS flows by matching drb_id before adding to DRB setup list
- Replace inline mapping code with helper function call
- Add assertion to verify at least one QoS flow is added per DRB
This commit fixes two related issues:
1. SDAP Header Mapping Bug (cucp_cuup_handler.c):
The original code incorrectly mapped SDAP header configuration from
internal E1AP representation to ASN.1 enum values. The internal
representation (`bearer_context_sdap_config_t`) uses true=present/false=absent,
while ASN.1 enum (`E1AP_SDAP_Configuration_t`) uses
0=present/1=absent. The fix correctly inverts the mapping:
- Internal true (1) → ASN.1 0 (present)
- Internal false (0) → ASN.1 1 (absent)
The commit also clarifies internal representation in the stack.
2. Test Overhead Adjustment (nr-cuup-load-test.c):
The change in (1) led to a failure in nr_cuup_functional_test
with assertion: "size % 4 == 0" in recv_ng()
- Changed UL packet overhead from 3 bytes to 2 bytes in sender_thread()
- Before the SDAP fix, the test incorrectly accounted for 3 bytes:
* 2 bytes PDCP header (correct)
* 1 byte SDAP header (incorrectly included)
- After the SDAP fix, SDAP headers are correctly set to absent, so
only 2 bytes (PDCP header) are needed
This ensures the test sends packets with the correct header size,
matching what CU-UP expects after the SDAP configuration fix.
The load test does not enable SDAP headers, therefore the original 3-byte
overhead was possibly a workaround for the SDAP header bug.
With the bug fixed, the test correctly uses 2-byte overhead (PDCP header).
This commit refactors the PDU Session Resource Modify Response message
structures to improve naming, documentation, and compliance with 3GPP TS 38.413 9.2.1.6.
Changes in NGAP:
- Rename qos_flow_tobe_modified_t to qos_flow_addmod_response_item_t to better
reflect its purpose as a QoS Flow Add or Modify Response Item IE (as per specs)
- Add mandatory AMF UE NGAP ID field to ngap_pdusession_modify_resp_t structure
- Optimize field types: change nb_of_pdusessions and nb_of_pdusessions_failed
from uint16_t to uint8_t (NGAP_MAX_PDU_SESSION limit) (ref 3GPP TS 38.413, 9.2.1.6)
- Update PDU Session Modify Response encoder to use amf_ue_ngap_id from the
message structure (pdusession_modify_resp_p->amf_ue_ngap_id) instead of
retrieving it from UE context (ue_context_p->amf_ue_ngap_id)
- Add comprehensive comments with 3GPP TS 38.413 section references throughout
Changes in RRC/NGAP:
- Populate amf_ue_ngap_id field in PDU Session Modify Response message from
UE context
- Update type reference to qos_flow_addmod_response_item_t
Add DRB To Remove List IE to PDU Session To Modify list, which is sent
in the Bearer Context Modification request. This allows the CUCP to
inform the CUUP about DRBs to be released in a specific PDU session
during a MODIFY procedure.
Changes:
* Add struct definition
* Add enc/dec/eq/cp func
* Add test
Implement TS 38.473 transparency for CellGroupConfig forwarding and handle re-establishment on a different DU
This MR implements the following fixes that are relevant in RRC
procedures (e.g. re-establishment, reconfiguration):
1. Transparent CellGroupConfig forwarding
This MR implements TS 38.473 transparency requirements by ensuring that
the CellGroupConfig IE is transparently forwarded from the gNB-DU to the
UE without any re-encoding at the gNB-CU. The CU stores and forwards the
encoded bytes transparently, while the DU is responsible for all
encoding and modifications (e.g., reestablishRLC flags). Motivation
Motivation: The 3GPP TS 38.473 specification mandates that the
CellGroupConfig IE shall be transparently signaled to the UE.
Previously, the CU was re-encoding CellGroupConfig depending on the
scenario, instead of retrieving it from the DU, violating the
transparency requirement. CU may decode for internal use but must not
re-encode for forwarding. Solution
Solution: Core Principle: The CU stores the encoded CellGroupConfig
bytes received from the DU and forwards them directly to the UE without
any re-encoding. The DU handles all encoding and modifications.
Key Changes:
1. Transparent Forwarding in RRC Reconfiguration
- Modified build_RRCReconfiguration_IEs() to use pre-encoded bytes
directly
- Changed parameter from cell_group_config to cgc (encoded byte
array with buffer and size)
2. Encoded Bytes Storage
- Added byte_array_t mcg field to RRC UE structure to store encoded
CellGroupConfig
- Added store_cgc() helper function to save encoded cell group in
the RRC UE Context at gNB (from F1AP messages)
3. DU Encoding Responsibilities
- Add gNB-DU Configuration Query IE support to trigger cgc encoding
to request CellGroupConfig from DU
- DU encodes CellGroupConfig with proper reestablishRLC flags
during re-establishment
- DU removes SRB1 from rlc-BearerToAddModList during
re-establishment (SRB1 re-establishment is done before
RRCReconfiguration)
4. New functions
- Add rrc_detect_reestablishment() function to detect
re-establishment during UE Context Modification
- Extracted rrc_gNB_first_reconfiguration_after_reestablishment()
function to handle first reconfiguration after re-establishment
- Added dump_cgc() and dump_mcg() utility functions for debugging
purposes
5. Re-establishment Flow
- rrc_gNB_process_RRCReestablishmentComplete() requests
CellGroupConfig from DU via gNB_DU_Configuration_Query in UE
Context Modification Request
- DU detects re-establishment and add reestablishRLC IEs
- CU stores encoded CGC from the UE Context Modification Response
and forwards it transparently in subsequent RRC Reconfiguration
Testing
Manual Testing:
- RRC re-establishment procedure completes successfully
- RRC Reconfiguration after re-establishment includes all DU-provided information
Issues fixed
Closes issue #837
2. Trigger UE Context Setup fallback upon reestablishment on DU
different from the original one
As per 38.401 §8.7: if the UE accesses a DU different from the original
one during re-establishment, the CU must trigger UE Context Setup toward
the new DU. This refers to steps 9-10 and steps 9’-10’. Either one or
the other can be executed during re-establishment.
e.g. if this happens during handover, it shall trigger a UE Context
Setup fallback on the CU.
This MR implements the required behavior by:
- Adding a new helper function rrc_handle_f1_ho_reestab_on_target() to
handle F1 handover reestablishment on target DU. The function triggers
UE Context Setup procedure when the UE reestablishes on the target DU
during an ongoing F1 handover.
- Calling this function when detecting that the UE is reestablishing on
the target DU during handover, i.e.: (1) from
handle_rrcReestablishmentComplete(), as per 38.401 §8.7, NOTE on steps
9-10: CU gets UL RRC MESSAGE TRANSFER from a DU different than the
original (2) from rrc_CU_process_ue_modification_required, as per
38.401 §8.7, NOTE on steps 9'-10': CU gets a UE CONTEXT MODIFICATION
REQUIRED from a DU different from the original one.
Also:
- add helper rrc_fill_f1_ue_context_setup and adopt it in handover
- move DRB list filler fill_drb_to_be_setup into rrc_gNB.c and rename it
rrc_fill_f1_drb_to_setup for consistency
See also TS 38.401 Figure 8.7-1 "RRC connection reestablishment
procedure" for reference
3. DU: Handle missing old UE context in DL RRC Message Transfer
During F1 handover reestablishment, the CU may forward a DL RRC Message
Transfer to the target DU with old_gNB_DU_ue_id included, even though
the target DU does not have the old UE context yet.
The code previously used AssertFatal when the old UE context was not
found, causing a crash: "CU claims we should know UE %04x, but we don't"
According to TS 38.473, the gNB-DU shall release the old gNB-DU UE F1AP ID only:
> if the gNB-DU identifies the UE-associated logical F1-connection If
> there is no matching connection, there is nothing to release.
Fix:
- Check if old UE context exists before accessing it
- If old UE does not exist, log error, clean up any stale F1 UE data,
and return early (do not deliver RRC message since reestablishment
can't be completed)
The goal is to address a recurrent issue in the F1 pipeline, see
jenkins-oai.eurecom.fr/job/RAN-SA-Handover-CN5G/514:
Assertion (oldUE) failed!
In dl_rrc_message_transfer() /oai-ran/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c:956
CU claims we should know UE 35ce, but we don't
This commit fixes the timing of SRB and DRB PDCP re-establishment
during RRC connection re-establishment to align with 3GPP TS 38.331
specifications.
Key Changes:
1. SRB1 activation and re-establishment (TS 38.331 5.3.7.4):
- Move SRB1 activation to rrc_gNB_generate_RRCReestablishment()
- Use SRB1 constant instead of magic number 1 for clarity
- Remove redundant security configuration loop (handled by
nr_pdcp_reestablishment internally)
2. SRB2 re-establishment (TS 38.331 5.3.5.6.3 SRB addition/modification):
- Move SRB2 PDCP re-establishment from rrc_gNB_process_RRCReestablishmentComplete()
to rrc_gNB_generate_dedicatedRRCReconfiguration(): per spec: SRB2
should be re-established in the first RRCReconfiguration after
re-establishment (with reestablishPDCP=true flag)
3. DRB re-establishment (TS 38.331 5.3.5.6.5 DRB addition/modification):
- Move cuup_notify_reestablishment() from rrc_gNB_process_RRCReestablishmentComplete()
to rrc_gNB_generate_dedicatedRRCReconfiguration(). e.g at the first
reconfiguration after reestablishment
- Ensures CU-UP is notified at the correct time
As per TS 38.401 §8.7: if the UE accesses a DU different from the original
one during re-establishment, the CU must trigger UE Context Setup toward
the new DU. This refers to steps 9-10 and steps 9'-10'. Either one or the
other can be executed during re-establishment.
e.g. if this happens during F1 handover, it shall trigger a
UE Context Setup fallback on the CU.
This commit implements the required behavior:
1. Detection mechanism:
- Add `old_du_assoc_id` field to `f1_ue_data_t` to store the original
DU association ID
- At RRCReestablishmentRequest: Store original `du_assoc_id` in
`old_du_assoc_id` and update `du_assoc_id` to the new DU
- At RRCReestablishmentComplete: Compare `old_du_assoc_id` with the
`assoc_id` from the Complete message to detect different DU
2. UE Context Setup trigger:
- In `rrc_gNB_process_RRCReestablishmentComplete()`: When different DU
is detected, call `rrc_f1_ue_context_setup_for_target_du()` to trigger
UE Context Setup procedure (per TS 38.401 §8.7, NOTE on steps 9-10)
upon reception of UL RRC MESSAGE TRANSFER
- In `rrc_CU_process_ue_modification_required()`: Refuse UE Context
Modification Required when `old_du_assoc_id != 0` to avoid conflicts
with the ongoing UE Context Setup procedure (per TS 38.401 §8.7, NOTE
on steps 9'-10')
3. UE Context Setup:
- Replace `clone_CellGroupConfig()` with `get_cellgroup_config()` in
UE Context Setup handler
- Call `update_cellgroup_for_reestablishment()` during UE Context Setup
when `reestablish_rlc` flag is set to prepare CellGroupConfig with
reestablishRLC flags
- Clean up `old_du_assoc_id` in `rrc_CU_process_ue_context_setup_response()`
- Add `free_ue_context_mod_req()` call after UE Context Modification request
4. Function signature updates:
- Update `handle_rrcReestablishmentComplete()` to accept `gNB_DU_ue_id`
and `assoc_id` parameters, change return type from `int` to `void`
- Update `rrc_gNB_process_RRCReestablishmentComplete()` to accept
`assoc_id` parameter
- Update `rrc_gNB_decode_dcch()` to accept and forward `assoc_id` parameter
Re-establishment on different DU flow (TS 38.401 §8.7, steps 9-10):
1. UE sends RRCReestablishmentRequest to new DU
2. DU forwards to CU via UL RRC MESSAGE TRANSFER
3. CU detects different DU (`assoc_id != ue_data.du_assoc_id`):
- Stores `old_du_assoc_id = ue_data.du_assoc_id` (original DU)
- Updates `ue_data.du_assoc_id = assoc_id` (new DU)
4. CU sends RRCReestablishment to UE
5. UE sends RRCReestablishmentComplete to new DU
6. DU forwards to CU via UL RRC MESSAGE TRANSFER
7. CU detects different DU scenario (with old_du_assoc_id):
- Triggers UE Context Setup Request to new DU via `rrc_f1_ue_context_setup_for_target_du()`
8. DU receives UE Context Setup Request:
- Detects re-establishment (`UE->reestablish_rlc` flag)
- Calls `update_cellgroup_for_reestablishment()` to set reestablishRLC flags
- Encodes CellGroupConfig with reestablishRLC flags and sends to CU
9. CU receives UE Context Setup Response:
- Stores encoded CellGroupConfig
- Clears `old_du_assoc_id = 0`
10. CU sends RRC Reconfiguration with transparent CellGroupConfig to UE
This commit implements transparent forwarding of CellGroupConfig
as required by TS 38.473, eliminating CU-side decode/re-encode
cycles that violate transparency requirements.
Main Design Change:
- Before: CU decoded CellGroupConfig from DU, stored in the UE
context then re-encoded when sending to UE. CU constructed
new CellGroupConfig after RRCReestablishmentComplete.
- After: CU requests CellGroupConfig from DU via UE Context Modification
Request with `gNB_DU_Configuration_Query=true`, DU sends CellGroupConfig
which CU stores as encoded `byte_array_t` and forwards transparently
via reconfiguration without decode/re-encode cycles
To this purpose, all decode operations of CellGroupConfig were removed
from DU and all encode operations were removed from the CU.
Key Changes:
CU:
- Replace NR_CellGroupConfig_t* masterCellGroup with byte_array_t mcg in
gNB_RRC_UE_t for storing encoded CellGroupConfig
- Rename cell_group_config to cgc in nr_rrc_reconfig_param_t for brevity
- Implement transparent forwarding in build_RRCReconfiguration_IEs()
- Add helper functions:
- `store_cgc()` to store encoded bytes
- `get_meas_gap_config()`: Decode MeasGapConfig from DU to CU response
- `rrc_detect_reestablishment()` to detect re-establishment by decoding
temporarily (only for detection)
- Remove legacy decode/re-encode paths in RRC message generation
- Update all CellGroupConfig storage to use encoded bytes
- Update reconfiguration generation to accept is_reestablishment parameter
DU:
- Add `get_cellgroup_config()` to select source (CellGroup vs reconfigCellGroup)
based on re-establishment state
- Add re-establishment detection logic in `ue_context_modification_request()`
- Add `update_cellgroup_for_reestablishment()` to set reestablishRLC flags and
remove SRB1 from bearer list
- When `gNB_DU_Configuration_Query` is present and re-establishment detected:
- Clones from reconfigCellGroup (which contains spCellConfig) instead of
CellGroup (where spCellConfig was removed)
- Sets `reestablishRLC` flags for all bearers except SRB1
- Removes SRB1 from bearer list (already re-established)
Data Structure Changes:
- gNB_RRC_UE_t: Add byte_array_t mcg field
- nr_rrc_reconfig_param_t: Change cell_group_config to cgc (byte_array_t*)
- Remove masterCellGroup field usage in favor of encoded mcg
New re-establishment flow:
1. UE sends RRCReestablishmentRequest
2. CU processes -> sends RRCReestablishment
3. CU sends RRCReestablishmentComplete
4. CU sends UE Context Modification Request to DU with `gNB_DU_Configuration_Query=true`
5. DU detects re-establishment (`UE->reestablish_rlc && UE->reconfigCellGroup != NULL`):
- Clones `UE->reconfigCellGroup` -> `new_CellGroup` (contains spCellConfig)
- Sets `reestablishRLC` flags for all bearers except SRB1
- Removes SRB1 from bearer list (already re-established)
- Encodes `new_CellGroup` and sends to CU
6. CU receives encoded CellGroupConfig -> stores in `UE->mcg` via `store_cgc()`
7. CU detects re-establishment via `rrc_detect_reestablishment()`
8. CU calls `rrc_gNB_generate_dedicatedRRCReconfiguration()` with `is_reestablishment=true`:
- Creates SRB/DRB lists with re-establishment flags
- Generates RRC Reconfiguration with transparent CellGroupConfig
- Sends to UE
Why spCellConfig must be added in the DU in case of re-establishment:
With transparent forwarding, CU requests CellGroupConfig from DU instead
of constructing it. During re-establishment, DU's runtime CellGroup has
spCellConfig = NULL (removed per TS 38.331 §5.3.7.2). However, for the
gNB_DU_Configuration_Query response, DU must provide a complete CellGroupConfig
including spCellConfig. Therefore, DU restores spCellConfig by encoding
reconfigCellGroup (with the original spCellConfig) in CellGroupConfig.
In the old design CU constructed CellGroupConfig itself in
`rrc_gNB_process_RRCReestablishmentComplete()` and used `spCellConfig`
from its stored `masterCellGroup`.
Closes#837
Apply CGC encoding through GNB-DU Configuration Query. This applies to the
pdu session release path (rrc_gNB_send_f1_drb_release_request) and E1 bearer
mod / DRB add+release path (rrc_gNB_generate_UeContextModificationRequest).
This is necessary to implement 3GPP TS 38.473 requirement for
gNB-DU Configuration Query IE in UE Context Modification Request:
"If the GNB-DU Configuration Query IE is contained in the UE CONTEXT
MODIFICATION REQUEST message, gNB-DU shall include the CellGroupConfig
IE in the DU To CU RRC Information IE in the UE CONTEXT MODIFICATION
RESPONSE message."
i.e.: The DU sends the CGC only when this IE is enabled in the REQ
message from the CU. The only other scenario according to the same
specs is when the Full Configuration IE is present. Outside of these
two cases, CGC shall not be sent.
Add debugging utilities dump_cgc() and dump_mcg() to decode and
print CellGroupConfig in XER format when DEBUG_ASN1 flag is enabled.
This helps debug RRC Reconfiguration messages containing masterCellGroup.
Add intermediate fallback to rrc_gNB_get_ue_context_by_rnti_any_du() in
re-establishment request handling to better handle cases where UE
re-establishes on a different DU.
RNTI is NOT globally unique - different DUs can assign the same RNTI to
different UEs. The assoc_id check in rrc_gNB_get_ue_context_by_rnti()
disambiguates RNTI across DUs and prevents returning the wrong UE.
However, during re-establishment on a different DU, du_assoc_id hasn't
been updated yet (message comes from new DU, but ue_data.du_assoc_id
still points to old DU), causing the primary lookup to fail even though
the UE exists.
The lookup now uses a three-tier fallback:
1. Primary: rrc_gNB_get_ue_context_by_rnti() with assoc_id check
(normal case: same DU)
2. Fallback 1: rrc_gNB_get_ue_context_by_rnti_any_du() by RNTI only
(re-establishment on different DU)
3. Fallback 2: rrc_gNB_get_ue_context_source_cell() using physCellId
(handover scenarios)
- Remove unused masterCellGroup_from_DU parameter from rrc_gNB_generate_RRCReestablishment() as it is not used in the RRC
re-establishment generation, RRCReestablishment message does not contain CellGroupConfig which is obtained later via UE Context Modification Request/Response
- Update function documentation
- Initialize security_parameters struct to zero for safety
- Add check on ciphering and integrity algorithm ranges
When a UE re-establishes on a different DU, the physCellId in the
re-establishment request (from the old cell) will differ from the
new DU's physCellId. The previous check incorrectly treated this as
a "too fast movement" scenario and triggered fallback to RRC setup.
This fix distinguishes between two scenarios:
1. Different DU scenario: physCellId differs because UE is on a
different DU - this is legitimate and should be allowed. UE
Context Setup will be triggered at RRCReestablishmentComplete.
2. Same DU but different physCellId: "too fast movement" scenario
- fallback to RRC setup as before.
The fix checks if assoc_id != ue_data.du_assoc_id to detect a
different DU scenario and allows re-establishment in that case.
This addresses the issue where re-establishment on a different DU
was incorrectly rejected, preventing proper UE Context Setup per
TS 38.401 Section 8.7.
Handle target DU UE context setup when handover preparation info
is unavailable (i.e. re-establishment scenario) by retrieving
secondary UE ID from F1 UE data.
rrc_f1_ue_context_setup_for_target_du is either applying to
handover or re-establishment. In the latter scenario, populate
DU UE ID, which should be known.
semi-manual remove of not used #define commands
As i was upset to see all these #define with no code under, i made a
global pass to remove the obvious cases semi-manual remove of not used
bodies
manual script, then a lot of manual review
grep -IRs "#define" ../openair* ../common/* ../executables/ ../nfapi/ ../radio/ | \
fgrep -v '(' | fgrep -v '//' |awk '{print $2}' | egrep -v "#define *$n"| \
while read n ; do
grep -IRs $n ../openair* ../common/* ../executables/ ../nfapi/ ../radio/ | grep -v "#define *$n" | grep -q $n || echo $n;
done
will give a decent list of #define never used. Then, I think we should
keep lists of # define when it comes from standards, even if the code
doesn't use it right now
Add Ethernet PDU session support and make PDU session request configurable
This MR adds support for Ethernet PDU sessions, and makes PDU sessions
configurable: per-PDU session ID, type (IPv4/IPv4v6/IPv6/Ethernet [1]),
DNN, NSSAI.
Concretely, it adds a new configuration file section pdu_sessions below
uicc0 that looks like this if everything is specified (default values
are shown):
uicc0:
[...]
pdu_sessions:
- id: 1
type: "IPv4"
nssai_sst: 1
nssai_sd: 0xffffff
dnn: "oai"
It is possible to list multiple PDU sessions (add new line - id: 2 to
request a second PDU session). It is backwards-compatible to the current
PDU session configuration (uicc0.dnn/nssai_sst/etc), the idea being that
either legacy or new configuration could be used, but (1) if
pdu_sessions exist, it will overwrite the legacy configuration, and (2)
multiple PDU sessions, and type, can only be configured using the new
config. The old parameters --extra-pdu-id and --default-pdu-id are not
accepted anymore. Documentation has been added to the UE tutorial.
It is possible to test an Ethernet PDU session [1]. It is possible to
test the PDU session inside the UE by verifying it has an TAP interface
oaitap_ue1, and ARPing the data network (arping has been added to
oai-nr-ue container for that purpose):
ip addr add 192.168.72.140/26 dev oaitap_ue1 # same subnet as data network!
ip link set dev oaitap_ue1 up
arping -c 20 -I oaitap_ue1 192.168.72.135 # will send ARP request in Ethernet frame to get IP address of data network
[1] See description MR !3769 for more information. On the UE side, only
the type has to be changed to "Ethernet".
NGAP: improve error handling in RRCReconfiguration from Handover Command decoding
This MR refactors doRRCReconfiguration_from_HandoverCommand for consistency and
safety, and enables NGAP Handover Cancel encoding/decoding.
- Refactored doRRCReconfiguration_from_HandoverCommand function:
- Changed signature to return byte_array_t instead of taking a buffer parameter
- Prevents buffer overflow by auto-sizing memory with uper_encode_to_new_buffer
- Input validation
- HandoverCommand structure validation
- Error handling and cleanup for encode/decode failures
- ASN.1 structure cleanup on all error paths
- Updated caller in rrc_gNB_NGAP.c: use new byte_array_t return signature,
added buffer cleanup with free_byte_array(), sends Handover Cancel to AMF on
decoding failure (source gNB)
- Improved error logging
- NGAP Handover Cancel encoding/decoding support
- Added missing Handover Cancel ack case handler for
NGAP_ProcedureCode_id_HandoverCancel in ngap_gNB_decode_initiating_message()
to decode and log incoming Handover Cancel Ack message
- Added NGAP_ProcedureCode_id_HandoverCancel to the list of supported
initiating message procedure codes in ngap_gNB_encode_initiating() allowing
the gNB to encode and send Handover Cancel messages
Note: The Handover Cancel procedure is already implemented elsewhere in the NGAP
stack; these changes complete support by ensuring the procedure code is
recognized in both encoder and decoder.
Closes#1043
- Add function documentation blocks for `rrc_fill_f1_ue_context_setup`,
`rrc_f1_ue_context_setup_for_target_du`, and `rrc_f1_ue_context_setup_from_e1_response`
explaining their purpose, parameters, and usage scenarios
- Add inline comments throughout these functions
Improve maintainability by centralizing common F1AP UE context setup
logic into reusable helper functions, enabling consistent handling
and clear serving/target DU entry points for different scenarios.
Code duplication prevention is a beneficial side effect, since at
least one helper function is adopted in subsequent commits.
Major changes:
- Move DRB list filler from external file into rrc_gNB.c and rename
fill_drb_to_be_setup to rrc_fill_f1_drb_to_setup for naming
consistency
- Add static helper rrc_fill_f1_ue_context_setup to populate common
fields shared between serving DU and target DU scenarios:
- Rename rrc_gNB_generate_UeContextSetupRequest to
rrc_f1_ue_context_setup_from_e1_response to clarify it prepares
F1AP context setup from E1AP bearer setup response for serving DU
- Add rrc_f1_ue_context_setup_for_target_du (for target DU in
handover/reestablishment scenarios)
- Adopt helper rrc_fill_f1_ue_context_setup in both functions
Defacto, the PDU session ID for noS1 modes is already hardcoded, as
starting the nr-softmodem with --noS1 --default-pdu-id 1 leads to
Assertion (entity != ((void *)0)) failed!
In start_sdap_tun_gnb_first_ue_default_pdu_session() openair2/SDAP/nr_sdap/nr_sdap.c:163
Further, the --default-pdu-id parameter will be deactivated in a later
commit, and we cannot rely on it. Therefore:
- hardcode noS1 PDU ID (also used in --do-ra/--phy-test modes) to 10 and
use in gNB&UE
- pass the PDU session ID used in SDAP entity initialization down to
start_sdap_tun_gnb_first_ue_default_pdu_session() to always use the
correct one
NR UE: add neighboring cell measurements and measurement report of event A3
This is a rework of MR !2385 (closed), the goal is to add neighboring cell
measurements and measurement report of event A3 for NR UE.
This MR was tested with:
- 3rd-party gNB
- 2 OAI-gNB-DUs
The neighboring cell measurements and measurement report of event A3 for OAI-UE
are working as expected.
While testing the gNB with two hypotetical neighbors, some issues were found
with A3 event configuration.
The configuration of neighbors is:
neighbour_list = (
{
nr_cellid = 12345679L;
neighbour_cell_configuration = (
{
gNB_ID = 0xba0;
nr_cellid = 720898;
physical_cellId = 1;
absoluteFrequencySSB= 621312;
subcarrierSpacing = 1;
band = 78;
plmn = { mcc = 505; mnc = 01; mnc_length = 2 };
tracking_area_code = 1;
},
{
gNB_ID = 0xea0;
nr_cellid = 1345678L;
physical_cellId = 2;
absoluteFrequencySSB= 640000;
subcarrierSpacing = 1;
band = 78;
plmn = { mcc = 505; mnc = 01; mnc_length = 2 };
tracking_area_code = 1;
}
);
}
);
There were two problems.
The first problem is:
- when only default A3 event is configured, it is duplicated in the
RRC Reconfiguration Report Config To AddMod list with IDs 4 and 5
To test this case, the event configuration is:
nr_measurement_configuration = {
Periodical = {
enable = 1;
includeBeamMeasurements = 1;
maxNrofRS_IndexesToReport = 4;
};
A2 = {
enable = 1;
threshold = 60;
time_to_trigger = 1;
};
A3 = (
{
physCellId = -1;
offset = 15;
hysteresis = 2;
time_to_trigger = 3
}
);
};
The second problem is:
- when configuring an A3 event with an unknown physCellId, the gNB
does not include any A3 event in the RRC Reconfiguration Report
Config To AddMod list (which is correct), but configures some
meas ID with nonexistant Report Config IDs
To test this case, the event configuration is:
nr_measurement_configuration = {
Periodical = {
enable = 1;
includeBeamMeasurements = 1;
maxNrofRS_IndexesToReport = 4;
};
A2 = {
enable = 1;
threshold = 60;
time_to_trigger = 1;
};
A3 = (
{
physCellId = 10;
offset = 15;
hysteresis = 2;
time_to_trigger = 3
}
);
};
Reworking A3 event configuration as done in this commit solves both
issues.
- Refactor function to return byte_array_t instead of taking buffer
parameter for consistency with other encoding functions
(do_RRCReconfiguration, do_HO_RRCReconfiguration) and to prevent buffer
overflow issues since the memory size is determined automatically
- Add comprehensive error checking:
* Input validation
* Check return of each decode (HandoverCommand
and RRCReconfiguration)
* Validate HandoverCommand structure before access
* Validate OCTET_STRING before decoding RRCReconfiguration
* Error handling and cleanup for enc/dec failures
- Update caller in rrc_gNB_NGAP.c
* use new signature
* free buffer
* send HO Cancel on decoding failure (source gNB)
Closes#1043
Fix bug "no AMF for UE"
It might happen that the RRC does not know the AMF UE NGAP ID, yet. Even
in that case, we should forward the release request to the NGAP module,
which can either forward a message to the AMF, or reply back to release
the UE. This avoids an error where the CU claims there was no AMF, when
there actually is.
One possible problematic behavior is if a UE disconnects before the gNB
receives an NGAP Initial Context Setup. In this case, the AMF UE NGAP ID
was not forwarded to the RRC (although it was known at NGAP), thus
blocking the release of the UE.
This is the main fix, the rest are minor fixes:
- store AMF UE NGAP ID as early as possible
- warn in MAC if UE unknown for UE context release command
- show TEIDs with correct endianness in GTP
- avoid NG Setup Failure+Setup log.
In the Initial Context Setup message, the NGAP forwards the AMF UE ID,
but not in the DL NAS Message, although 38.413 says, in $8.3.1.2 either
> The NG-RAN node shall use the AMF UE NGAP ID IE and RAN UE NGAP ID IE
> received in the INITIAL CONTEXT SETUP REQUEST message as identification
> of the logical connection
or in $8.6.2.2
> The NG-RAN node shall use the AMF UE NGAP ID IE and RAN UE NGAP ID IE
> received in the DOWNLINK NAS TRANSPORT message as identification of the
> logical connection
So forward in both cases for harmonization.
It might happen that the RRC does not know the AMF UE NGAP ID, yet. Even
in that case, we should forward the release request to the NGAP module,
which can either forward a message to the AMF, or reply back to release
the UE.
Reported-By: Jegor Zelenjak <jzelenjak@proton.me>
NR NGAP (N2HO) : Fix Time UE Stayed in Cell IE type and calculation
According to 3GPP TS 38.413, the 'Time UE Stayed in Cell' IE is an
integer ranging from 0 to 4095. This patch updates the data structure
to reflect the correct bit width and implements the dynamic calculation
based on the UE's residence time.
- Change time_in_cell from long to uint16_t in ngap_messages_types.h.
- Replace dummy value with real-time calculation in rrc_gNB_NGAP.c.
- Implement a ceiling of 4095 to comply with the 12-bit protocol limit.
Ref: 3GPP TS 38.413 Section 9.3.1.97
Refactor key derivation logic to properly handle Next Hop (NH) chain
synchronization according to 3GPP TS 33.501 specifications for both RRC
Reestablishment and Master Key Update procedures.
Changes in rrc_gNB.c:
- Clarify key derivation in rrc_gNB_generate_RRCReestablishment by explicitly
selecting base key (NH or KgNB) based on nh_ncc value
- Add comment explaining vertical vs horizontal derivation logic
Changes in rrc_UE.c:
Refactored the NH chain synchronization and key derivation code to match
TS 33.501 terminology:
- nr_sync_nh_chain(): Common helper to synchronize NH parameter chain per
TS 33.501 Annex A.10, supporting both Master Key Update and RRC Reestablishment
procedures
- nr_derive_kgnb_horizontal(): Derive KNG-RAN* from current KgNB when NCC values
match (horizontal derivation per TS 33.501 A.11/A.12)
- nr_derive_kgnb_vertical(): Derive KNG-RAN* from synchronized NH after NH chain
sync (vertical derivation per TS 33.501 A.11/A.12)
- nr_update_kgnb_from_ncc(): Unified function implementing TS 33.501 6.9.2.3.4
logic for updating KgNB based on received nextHopChainingCount
- Refactor as_security_key_update(): Use new nr_update_kgnb_from_ncc() helper
function for cleaner, more maintainable code
- Fix nr_rrc_ue_process_rrcReestablishment(): Properly handle received
nextHopChainingCount and update KgNB using unified helper function
- Replaced the previous nr_rrc_nh_update() helper with these functions to
improve clarity and alignment with the specification.
- Add debug logging for key derivation process
Key NAS deriver utils:
- update derive_kgnb documentation and protect input keys with const attribute
Closes#857
According to 3GPP TS 38.413, the 'Time UE Stayed in Cell' IE is an
integer ranging from 0 to 4095. This patch updates the data structure
to reflect the correct bit width and implements the dynamic calculation
based on the UE's residence time.
- Change time_in_cell from long to uint16_t in ngap_messages_types.h.
- Replace dummy value with real-time calculation in rrc_gNB_NGAP.c.
- Implement a ceiling of 4095 to comply with the 12-bit protocol limit.
Ref: 3GPP TS 38.413 Section 9.3.1.97
Per TS 33.501 6.9.2.3.4 and Fig 6.9.2.1.1-1, when sending
RRCReestablishment with nextHopChainingCount, the gNB is staying at
the same NCC level (not advancing). Therefore, horizontal derivation
from the currently active KgNB must be used, not vertical derivation
from NH.
Vertical derivation (from NH) is only used when advancing to a new
NCC level, which happens during handover or masterKeyUpdate procedures.
The previous implementation incorrectly used vertical derivation from
NH whenever nh_ncc > 0, which caused key mismatch between gNB and UE
during reestablishment after handover, leading to integrity check
failures.
This fix ensures both gNB and UE use horizontal derivation when
nextHopChainingCount matches the current NCC level, aligning with the
specification's "virtual NH at NCC=0" model where:
- Horizontal derivation = derive KNG-RAN* from currently active KgNB
- Vertical derivation = derive KNG-RAN* from NH (only when advancing NCC)
These logs are very helpful to identify cell configuration
changes in MAC/PHY, for monitoring purposes, and to rapidly
signal integrity failures during re-establishment.
The RNTI from the target context was not updated after HO acknowledge
this led to a failure in the first re-establishment after HO.
This commit is introducing the function nr_rrc_apply_target_context
in nr_rrc_n2_ho_acknowledge() and also updates the cell ID for
consistency.
Refactor handover target context application logic into a reusable
function nr_rrc_apply_target_context() that updates both F1AP
associations (secondary UE and DU association) and RNTI from the
target handover context.
And apply to rrc_CU_process_ue_context_modification_response()
Per TS 33.501 6.9.2.3.4 and Fig 6.9.2.1.1-1, when sending
RRCReestablishment with nextHopChainingCount, the gNB is staying at
the same NCC level (not advancing). Therefore, horizontal derivation
from the currently active KgNB must be used, not vertical derivation
from NH.
Vertical derivation (from NH) is only used when advancing to a new
NCC level, which happens during handover or masterKeyUpdate procedures.
The previous implementation incorrectly used vertical derivation from
NH whenever nh_ncc > 0, which caused key mismatch between gNB and UE
during reestablishment after handover, leading to integrity check
failures.
This fix ensures both gNB and UE use horizontal derivation when
nextHopChainingCount matches the current NCC level, aligning with the
specification's "virtual NH at NCC=0" model where:
- Horizontal derivation = derive KNG-RAN* from currently active KgNB
- Vertical derivation = derive KNG-RAN* from NH (only when advancing NCC)
Refactor key derivation logic to properly handle Next Hop (NH) chain
synchronization according to 3GPP TS 33.501 specifications for both
RRC Reestablishment and Master Key Update procedures.
Changes in rrc_gNB.c:
- Clarify key derivation in rrc_gNB_generate_RRCReestablishment by
explicitly selecting base key (NH or KgNB) based on nh_ncc value
- Add comment explaining vertical vs horizontal derivation logic
Changes in rrc_UE.c:
- Add nr_sync_nh_chain(): Common helper to synchronize NH parameter
chain per TS 33.501 Annex A.10, supporting both Master Key Update
and RRC Reestablishment procedures
- Add nr_derive_kgnb_horizontal(): Derive KNG-RAN* from current KgNB
when NCC values match (horizontal derivation per TS 33.501 A.11/A.12)
- Add nr_derive_kgnb_vertical(): Derive KNG-RAN* from synchronized NH
after NH chain sync (vertical derivation per TS 33.501 A.11/A.12)
- Add nr_update_kgnb_from_ncc(): Unified function implementing TS 33.501
6.9.2.3.4 logic for updating KgNB based on received nextHopChainingCount
- Refactor as_security_key_update(): Use new nr_update_kgnb_from_ncc()
helper function for cleaner, more maintainable code
- Fix nr_rrc_ue_process_rrcReestablishment(): Properly handle received
nextHopChainingCount and update KgNB using unified helper function
- Add debug logging for key derivation process
Key NAS deriver utils:
- update derive_kgnb documentation and protect input keys with const attribute