Expand RRC usage and handover documentation to describe the two-level
neighbour configuration layout, lookup-key semantics,
and config-time SIB4 grouping behaviour. Expand the example config
to include a `frequency_list` block and per-neighbour SIB3/SIB4
offset fields. Add SIB2 config example.
Update handover-tutorial.md to describe the same nested model and
note that F1 and N2 handover share the same serving-cell keyed
mapping.
Add documentation about SIB3/SIB4 and MeasGaps implementation
in OAI with stress on the shared neighbour configuration data model.
Update FEATURE_SET.
Update the shared neighbour config used by the F1 rfsim pipeline to
enable CU-provided SIB2 and neighbour-derived SIB3/SIB4 inputs.
In `ci-scripts/conf_files/gnb-cu.sa.band78.106prb.conf`
- Add `cu_sibs = (2, 3, 4)
In `ci-scripts/conf_files/neighbour-config.conf`:
- Add a complete `sib2_config` block
- Add `frequency_list` / `frequency_config` for inter-frequency SIB4 fields
- Extend both neighbour entries with per-cell offsets
Add encode/decode helpers and basic round-trip tests for NR SIB2, SIB3
and SIB4 in test_asn1_msg.cpp to ensure we produce decodable messages
with expected fields. Extend SIB4 coverage with an
inter_freq_carrier_freq_info_ranges test that exercises boundary and
out-of-range values for carrier reselection parameters and checks
encoder failures for invalid configurations.
Changes:
- Introduce encode_and_decode_sib2, encode_and_decode_sib3 and
encode_and_decode_sib4 helpers that call do_SIB2_NR, do_SIB3_NR,
do_SIB4_NR and uper_decode and assert non-empty, non-null byte
arrays and successful decoding.
- Add sib2_basic_encode_decode, sib3_basic_encode_decode and
sib4_basic_encode_decode tests that populate minimal but
representative NR_SIB2_t, NR_SIB3_t and NR_SIB4_t instances and
verify selected decoded fields match the originals.
- Add inter_freq_carrier_freq_info_ranges test that builds an NR_SIB4_t
with NR_InterFreqCarrierFreqInfo_t and varies different offsets and
thresholds to confirm valid combinations encode and invalid ones
are rejected.
- Add comprehensive documentation header explaining the structure's role
as single source of truth for neighbor cell information across multiple
protocols (NGAP/XnAP handover, measurement config, DU validation, SIB3/SIB4)
- Add detailed field comments documenting protocol-specific mappings:
* Core identification fields (gNB_ID, nrcell_id, physicalCellId)
* Frequency/RF parameters (absoluteFrequencySSB, subcarrierSpacing, band)
* Handover target identification (plmn, tac)
- Document NGAP/XnAP IE mappings for plmn and tac fields
Remove the isIntraFrequencyNeighbour field and all code that sets or
uses it, simplifying neighbour cell handling and avoiding redundant
state in the RRC gNB code. The flag duplicated information that can be
derived from the neighbour absoluteFrequencySSB and the serving cell
SSB ARFCN, and intra-frequency neighbours are logged in the SIB3
preparation flow.
Changes:
- Remove isIntraFrequencyNeighbour from nr_neighbour_cell_t in
openair2/RRC/NR/nr_rrc_defs.h
- Delete is_intra_frequency_neighbour() and
label_intra_frequency_neighbours() helpers from
openair2/RRC/NR/rrc_gNB_du.c
- Remove calls to label_intra_frequency_neighbours() from
rrc_gNB_process_f1_setup_req() and
rrc_gNB_process_f1_du_configuration_update() in rrc_gNB_du.c
- Stop setting .isIntraFrequencyNeighbour in the local
nr_neighbour_cell_t neighbourConfig initializer in
openair2/RRC/NR/rrc_gNB_mobility.c
Add SIB4 encode/decode helpers and populate SIB4 from configured
inter-frequency carriers and neighbour cells, wiring it into DU F1
Setup handling and MAC SystemInformation.
Changes:
- Add do_SIB4_NR() and NR_SIB4.h inclusion in asn1_msg.c/asn1_msg.h to
UPER-encode NR_SIB4_t into a byte_array_t.
- Extend nr_mac_configure_other_sib() in NR_MAC_gNB/config.c with an
NR_SIB_4 case that validates the SIB container, decodes NR_SIB4_t via
uper_decode, logs failures, and appends SIB4 to SystemInformation.
- Introduce build_inter_freq_carrier_from_cfg() and
get_sib4_inter_freq_neighbors() in rrc_gNB_du.c to build
NR_InterFreqCarrierFreqInfo_t and NR_SIB4_t from inter-frequency and
neighbour cell configuration, skipping invalid or empty carriers.
- Handle NR_SIB_4 in rrc_gNB_process_f1_setup_req() by deriving SIB4
from neighbour/inter-frequency configuration, encoding it with
do_SIB4_NR(), validating the resulting byte_array_t and adding the SI
message for the DU cell when encoding succeeds.
Introduce NR SIB3 encoding in RRC and wire SIB3 neighbour information
into CU–DU F1 Setup and DU SystemInformation. Extend MAC to decode NR
SIB3 from CU-provided SIB containers and attach the decoded SIB3 to the
DU SystemInformation structure.
Changes:
- Add NR_SIB3 ASN.1 include and a do_SIB3_NR() encoder in asn1_msg
so SIB3 can be serialized into a byte_array_t buffer.
- Introduce get_q_offset_asn1() and get_sib3_intra_freq_neighbors() in
rrc_gNB_du.c to build an intra-frequency neighbour cell list for SIB3,
mapping q_OffsetCell dB values to NR_Q_OffsetRange and optionally
filling q_RxLevMinOffsetCell and q_QualMinOffsetCell.
- Limit the number of intra-frequency neighbours in SIB3 to
NR_maxCellIntra, logging a warning and skipping additional cells when
the limit is reached.
- Hook SIB3 construction and encoding into rrc_gNB_process_f1_setup_req()
so SIB type 3 entries are added to the F1 Setup Response when
neighbour configuration and matching neighbours are available.
- Handle NR_SIB_3 in nr_mac_configure_other_sib() by validating the CU
SIB3 container buffer, decoding it with uper_decode into an NR_SIB3_t,
and attaching the resulting SIB3 to the MAC SystemInformation via
add_sib_to_systeminformation().
Introduce typed SIB3/SIB4 neighbour and inter-frequency carrier
configuration structures, wire them into the RRC neighbour and gNB
instances, and centralise parsing and bounds checking of per-frequency
SIB4 parameters from the gNB frequency list.
Changes:
- Define SIB3/SIB4 reselection and offset bound macros in gnb_config.c
and apply them when parsing SIB4 frequency_config and
per-carrier q_RxLevMin/t_ReselectionNR.
- Add add_inter_freq and parse_inter_freq_list helpers in gnb_config.c
to populate a shared inter_freqs seq_arr_t from gNB_CONFIG_STRING_GNB_LIST
frequency_list entries, enforcing unique (ARFCN,SCS) combinations and
logging duplicates.
- Extend neighbour cell parameters in gnb_paramdef.h with SIB3 per-
neighbour offset fields and define frequency_list/frequency_config
option names, descriptor tables, and index constants for SIB4 inter-
frequency configuration.
- Introduce nr_neighbour_cell_neighbor_offset_t, nr_neighbour_cell_sib3_t,
nr_neighbour_cell_sib4_freq_t, nr_neighbour_cell_sib4_t, and
nr_inter_freq_cfg_t in nr_rrc_defs.h, and extend nr_neighbour_cell_t
and gNB_RRC_INST with sib3/sib4 and inter_freqs members respectively.
- udpated fill_neighbour_cell_configuration to use GET_PARAMS_LIST
with params bound check
Introduce a typed SIB2 cell reselection configuration, load it from the
gNB configuration into the RRC gNB instance, and use it to build and
encode SIB2 instead of relying on a fixed SIB2 definition.
Validate SIB2 parameters against explicit bounds and make the SIB2
encoder consume a pre-built ASN.1 structure with safer error handling.
Changes:
- Add SIB2 mobility timer and q-HystSF enums plus SIB2 config structs
(`sib2_speed_state_reselection_pars_t`, `sib2_config_t`) and a
`sib2_config` field on `gNB_RRC_INST` in `nr_rrc_defs.h`.
- Define SIB2 configuration option names, defaults
(`GNB_CONFIG_STRING_SIB2_*`, `GNBSIB2PARAMS_DESC`)
in `gnb_paramdef.h` for q_Hyst, thresholds, mobility timers, scaling
factors and deriveSSB_IndexFromCell.
- Add `sib2_config` parameter keys, defaults, and range/value checks in
`gnb_paramdef.h` (`GNBSIB2PARAMS_DESC`).
- Add SIB2 `fill_sib2_configuration()` in `gnb_config.c` to read SIB2
parameters from the config file log the resulting configuration and
store it in `rrc->sib2_config` via `RCconfig_NRRRC()`.
- Add `get_q_hyst_asn1()` and `get_sib2_from_cfg()` in `rrc_gNB_du.c`, and
update `rrc_gNB_process_f1_setup_req()` to encode/add SIB2 from config with
explicit encode-failure handling and logging.
- Change `do_SIB2_NR` signature in `asn1_msg.h/.c` to
`byte_array_t do_SIB2_NR(const NR_SIB2_t *sib2)`, remove internal default
SIB2 construction, and add ASN.1 constraint/encode error logging.
Unify SIB container handling by introducing a typed SIB enum and storing
SIB payloads as byte_array_t across common NR types, F1AP helpers, MAC,
and RRC DU setup code.
Changes:
- Include byte_array support in nr_common.h, add nr_sib_type_t (NR_SIB_1–NR_SIB_21),
and change nr_SIBs_t to hold only nr_sib_type_t SIB_type.
- Switch f1ap_sib_msg_t in f1ap_messages_types.h to use a byte_array_t SI_container
instead of raw pointer and length fields.
- Update F1AP encode/decode, equality, copy, and free helpers in
f1ap_interface_management.c to work on SI_container.buf / SI_container.len and
use eq_byte_array, copy_byte_array, and free_byte_array.
- Adapt F1AP tests in f1ap_lib_test.c to build and inspect SIB containers via
SI_container.buf and SI_container.len.
- Replace magic SIB numbers with nr_sib_type_t values in gnb_config.c
(get_sys_info and fill_du_sibs) to validate and configure DU SIBs.
- Rework nr_mac_configure_other_sib in NR_MAC_gNB/config.c to decode SIB2
from a byte_array_t container, fix freeing by releasing the decoded sib2 on
failure, and use NR_SIB_2 / NR_SIB_19 for CU/DU SIB selection.
- Add an add_si_msg helper in rrc_gNB_du.c and refactor the SIB2 branch of
rrc_gNB_process_f1_setup_req to populate cell->SI_msg from encoded local
byte array while iterating SIBs with FOR_EACH_SEQ_ARR.
Tighten neighbour-cell config parsing by enforcing parameter constraints in
the descriptor and switching parsing code to name-based lookups with gpd.
Changes:
- Update `GNBNEIGHBOURCELLPARAMS_DESC` in `openair2/GNB_APP/gnb_paramdef.h`
to add checks for `physical id`, `absoluteFrequencySSB`, `scs`, `band`
`tracking_area_code`.
- Remove neighbour-cell parameter index macros.
- Refactor `parse_neighbour_cells_list` in `openair2/GNB_APP/gnb_config.c`
to use `gpd()` lookups for neighbour fields instead of fixed indexes.
- Extend `parse_neighbour_cells_list` with an `n_cell_params` argument and
update `fill_neighbour_cell_configuration` to pass
`sizeofArray(ncell_params)`.
Inline neighbour cell arrays into the RRC neighbour configuration and
update RRC/DU helpers to use const-aware access and shared iteration
helpers when walking neighbour lists and building measurement configs.
Changes:
- Change neighbour_cells in neighbour_cell_configuration_t from a
seq_arr_t * to an embedded seq_arr_t field.
- Initialize and populate the embedded neighbour_cells directly in
parse_neighbour_cells_list in gnb_config.c, dropping dynamic
allocation of the neighbour list container.
- Refactor get_neighbour_cell_by_pci and nr_rrc_get_measconfig in
rrc_gNB.c to access the embedded neighbour_cells via const pointers,
introduce a local meas_cfg and a3_event_list, and iterate neighbour
cells with FOR_EACH_SEQ_ARR.
- Treat neighbour cell configuration entries as const in rrc_gNB_du.c
(get_cell_neighbour_list, label_intra_frequency_neighbours,
valid_du_in_neighbour_configs) and iterate neighbour lists with
FOR_EACH_SEQ_ARR instead of index-based loops.
Outer gNB neighbour_list entries now only declare the serving cell
nr_cellid. The code resolves that field with gpd instead of a fixed column
index.
Changes:
- gnb_paramdef.h: remove unused NEIGHBOUR_CELL_PHYSICAL_ID from
GNB_NEIGHBOUR_LIST_PARAM_LIST (keep NRCELLID only).
- gnb_config.c: in fill_neighbour_cell_configuration, set nr_cell_id
from gpd
Refactor gNB configuration code to share PLMN extraction logic and to
split neighbour-cell configuration into smaller helpers with safer
allocation and clearer list handling.
Changes:
- Add `extract_plmn_from_params()` in `gnb_config_common.c` and declare
it in `gnb_config_common.h` to centralize PLMN extraction from
`paramdef_t`.
- Update `set_plmn_config()` to use `extract_plmn_from_params()` when
filling the PLMN array instead of duplicating field assignments.
- Refactor `fill_neighbour_cell_configuration()` in `gnb_config.c` to
delegate per-cell neighbour parsing to
`parse_neighbour_cells_list()` and sorting to
`sort_neighbour_configuration()`, simplifying the main loop.
- Use `extract_plmn_from_params()` when parsing neighbour PLMNs in
`parse_neighbour_cells_list()` and log each neighbour with its PLMN,
PCI, and other radio parameters before adding it to the sequence.
- Switch allocation of `rrc->neighbour_cell_configuration` in
`fill_neighbour_cell_configuration()` from `malloc` to
`malloc_or_fail()` to enforce consistent handling of allocation
failures.
Change 1: config_check_intval() now uses the correct integer pointer for TYPE_INT
Problem: config_check_intval() previously dereferenced param->uptr regardless
of param->type. For parameters declared as signed (TYPE_INT / TYPE_INT32), the
active union member is param->iptr, and param->uptr may be NULL -> using uptr
makes validation unsafe and type-inconsistent.
What changed: Updated config_check_intval() behavior (signature unchanged).
Handle both param->type, param->iptr and param->uptr.
Change 1: new config_check_uintrange() for unsigned range constraints
Problem: there was a signed range checker (config_check_intrange()) that reads
param->iptr, but there was no dedicated unsigned range validator using param->uptr.
What changed: added config_check_uintrange() in config_userapi.h/.c
The new function reads param->uptr as uint32_t and validates against
param->chkPptr->s2.okintrange[] endpoints.
Change 3: constify input params for f2 function pointers
Problem: checkedparam_t.s2.f2 was typed with non-const input params, even though
range checks only read. A safer const-safe signature is required.
What changed: s2.f2 now takes const configmodule_interface_t *
and const paramdef_t *. config_check_intrange() and config_check_uintrange() use
the same const-qualified parameters.
Ensure the CU-CP only sets up PDU sessions that are not already
established for the UE, skipping duplicates while keeping the NG UE
context valid. This aligns with 3GPP TS 38.413 PDU Session setup
semantics for duplicate session IDs
Changes:
- Change rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ to scan requested
PDU sessions and detect IDs that already exist in UE->pduSessions with
PDU_SESSION_STATUS_ESTABLISHED
- Log a warning and skip already established PDU session IDs so they are
not added to UE->initial_pdus
- Collect only non-established PDU sessions into a temporary stack array,
allocate UE->initial_pdus with the exact count, copy them in, update
UE->n_initial_pdu, and only refresh UE AMBR when there is at least one
session to set up
Ensure DRBs from multiple PDU sessions are appended into the F1 DRB array
without overwriting previously filled entries.
Update fill_drb_to_be_setup_from_e1_resp to call fill_f1_drbs_from_e1
with &drbs[nb_drb] so each PDU session’s DRBs are written after the
current count
Paging messages are classified as non-UE-associated signalling per
3GPP TS 38.412 clause 7 (TL), which requires them to be sent on
stream 0 (or a reserved stream pair).
Paging message is received when UE is in RRC_IDLE or RRC_INACTIVE
state, as the RAN has no active UE context and paging targets the
UE by 5G-S-TMSI rather than RAN-UE-NGAP-ID.
The previous implementation incorrectly rejected paging messages
received on stream 0, causing paging failures when using Open5GS AMF.
Changes:
- Accept paging on stream 0 (non-UE-associated signalling)
- Reject paging on non-zero streams (UE-associated streams)
- Add documentation
RRC now builds F1AP paging messages directly by calling F1AP/direct
callbacks and aligning the CU/DU intergace with the F1AP design in the CU.
Messages are forwarded based on TAI-based cell matching across DUs.
- Remove F1AP_PAGING_IND message def and f1ap_paging_ind_t.
RRC no longer sends ITTI F1AP_PAGING_IND; it builds f1ap_paging_t
and passes it to the DU path.
- rrc_gNB_process_PAGING_IND: new signature (rrc, instance, msg)
with const where appropriate; call in rrc_gnb_task() updated.
- NGAP handler logic: For each TAI, match (PLMN + TAC) to
rrc->configuration; collect matching TAIs. Build one f1ap_paging_t
(5G-S-TMSI via nr_construct_5g_s_tmsi(), identity type
F1AP_PAGING_IDENTITY_CN_UE, optional drx/priority/origin copied
from ngap_paging_ind_t), call rrc_send_paging_to_dus(), then
free_f1ap_paging(). Remove the previous AssertFatal stub, CC loop,
NODE_IS_CU branch, and UE lookup logic: it is now handled by
F1AP/direct CU callbacks.
- rrc_gNB_du: Add rrc_send_paging_to_dus(rrc, tais, n_tai, msg).
Iterate DUs with RB_FOREACH; for each DU, fill msg->cells from
du->cells whose (PLMN + TAC) matches any requested TAI, set
n_cells, then call rrc->mac_rrc.paging_transfer(du->assoc_id,
msg). Skip DUs with no matching cells. Prevents duplicate paging
when multiple TAIs map to the same PLMN.
Introduce paging_transfer in the mac_rrc_dl interface so the CU can pass
paging to the DU (F1 or direct). Use the F1AP paging lib on both CU and DU
for decode/free and to avoid leaking the message after send.
- Add f1_paging_transfer_func_t and paging_transfer to nr_mac_rrc_dl_if_s
(mac_rrc_dl.h, nr_rrc_defs.h).
- F1AP path: paging_f1ap() allocates F1AP_PAGING, copies with cp_f1ap_paging(),
sends via ITTI to TASK_CU_F1. Direct path: f1_paging_transfer_direct() stub
- CU task: call free_f1ap_paging() after CU_send_Paging() to release the message.
- DU: DU_handle_Paging() uses decode_f1ap_paging()/free_f1ap_paging() from lib,
returns on decode failure; remove inline ASN.1 IE parsing.
- cleanup outdated header comments in header files
- Left a TODO not in DU code to build PCCH (in F1 and direct paths)
- Add F1AP_PAGING message type and macro; F1AP defines Paging, not
Paging Indication. CU task now handles F1AP_PAGING instead of
F1AP_PAGING_IND.
- In CU_send_Paging(): take const f1ap_paging_t *; replace inline
ASN.1 encoding with encode_f1ap_paging(); refine memory management;
clean up in the process
Note: F1AP_PAGING_IND definitions left in place and still used in the
RRC callback - to be removed in a follow-up commit.
Add F1AP Paging library and new message type to follow the existing F1AP
library pattern and to support multi-cell paging and both RAN UE (I-RNTI)
and CN UE (5G-S-TMSI) paging identities at the library level per TS 38.473.
* New library (f1ap_paging.c/h, f1ap_lib_includes.h, CMakeLists.txt)
- Implement encode/decode/copy/eq/free for F1AP Paging (procedure 9.2.6).
- Add ASN.1 includes for Paging, PagingIdentity, CN/RAN UE identities.
- Enables unit testing of Paging enc/dec in f1ap_lib_test.c.
* New types in f1ap_messages_types.h (existing f1ap_paging_ind_t unchanged)
- f1ap_paging_t: UE Identity Index, paging identity (union + type enum),
optional paging_drx, paging_priority, paging_origin, and paging_cells[].
- f1ap_paging_cell_item_t, f1ap_paging_identity_type_t, f1ap_paging_identity_t
for multi-cell list and RAN/CN identity discrimination.
- Paging Origin IE is optional per F1AP 8.7.1.2.
Tests: test_f1ap_paging() roundtrip and copy for CN UE (5G-S-TMSI) and
RAN UE (I-RNTI) cases, with optional IEs.
- Refactor ngap_paging_ind_t (openair2/COMMON/ngap_messages_types.h):
- optional paging_drx and paging_priority as pointers
- TAI list as tai_list[] and n_tai
- add optional IEs: Paging Origin, Paging Attempt Information,
UE Radio Capability for Paging.
- Introduce nr_tai_t, ngap_paging_attempt_info_t, ngap_paging_origin_t;
- generate paging enums via FOREACH macros.
- Add NGAP Paging encode/decode/eq/free in openair3/NGAP/ngap_gNB_paging.c
(encode_ng_paging, decode_ng_paging, eq_ng_paging, free_ng_paging).
- Replace inline Paging decode in ngap_gNB_handle_paging() with
decode_ng_paging() and add error handling; add eq_ngap_plmn() in
ngap_common.
- Update rrc_gNB_NGAP.c to use tai_list/n_tai and optional paging_drx
when forwarding paging to F1AP.
- Add ASN.1 includes for Paging in ngap_msg_includes.h; register
ngap_gNB_paging.c in root CMakeLists.txt.
- Add NGAP unit test (openair3/NGAP/tests/ngap_lib_test.c): encode/decode
roundtrip for Paging; tests subdirectory and executable under
ENABLE_TESTS in openair3/NGAP/CMakeLists.txt.
ngap_common.h is for common IEs enc/dec functions, utilities
should go into a separate file. Changes in this commit:
* Add ngap_utils.h (utilities)
* Move helper macros (NGAP_ERROR, NGAP_DEBUG, NGAP_FIND_PROTOCOLIE_BY_ID, etc.) to ngap_utils.h
* Move equality check macros (_NGAP_EQ_CHECK_*) to ngap_utils.h
* Clean up includes
This change is preparatory to the introduction the paging lib with unit
tests, with the goal of reducing the inter-dependency between concurrent
NGAP libs.
TO_ENUM/TO_TEXT are already used in NAS, and can be adopted in NGAP.
To avoid duplication, the following changes are introduced:
* Move text_info_t, TO_ENUM, TO_TEXT to common/utils/utils.h
* Include utils.h include to ngap_messages_types.h, fgs_nas_utils.h, and fgmm_lib.h
* RRC establishment cause: refactor to FOREACH_RRC_ESTABLISHMENT_CAUSE macro
* Cause Group: refactor to FOREACH_CAUSE_GROUP macro
* Radio Network Cause: refactor to FOREACH_CAUSE_RADIO_NETWORK macro
* Protocol Cause: refactor to FOREACH_CAUSE_PROTOCOL macro
This change is preparatory to the introduction the paging lib with unit
tests, with the goal of reducing the inter-dependency between concurrent
NGAP libs.
These conversion functions will be needed across different
NGAP libraries upon refactoring: tnl_to_bitstring, bitstring_to_tnl
Therefore, they are moved to the common lib.
PDU session related NGAP messages do not belong to NAS procedures lib.
* Create ngap_gNB_pdu_session_management.c and .h
* Move out ngap_gNB_pdusession_setup_resp, ngap_gNB_pdusession_modify_resp,
ngap_gNB_pdusession_release_resp from ngap_gNB_nas_procedures.c
* Move encode_ngap_pdusession_setup_response_transfer to ngap_common.c:
this transfer IE is common used both in PDU Session Management and
Initial Context Setup, so it's moved to the common lib
* Add ngap_gNB_pdu_session_management.c to CMakeLists.txt
This commit centralizes equality-check behavior and removes duplicated
macro implementations across protocol stacks.
Major changes:
- add `common/utils/eq_check.h` with shared `_EQ_CHECK_*`,
`EQ_CHECK_GENERIC`, and optional-IE pointer helpers
- replace E1AP/F1AP/NAS local equality macros and call sites with
the shared helpers
- remove duplicated layer-specific error/equality macro definitions from
common headers and switch includes to `eq_check.h`
- update CMake test flags to define `ENABLE_TESTS` for `e1ap_lib`,
and 5GS NAS libraries; drop `E1AP_LOG_ERRORS` - equality-check/error
printing is now consistently controlled by `ENABLE_TESTS`
Centralizes 5G-S-TMSI bit manipulation logic for consistency and
maintainability. All manual bit operations replaced with documented
helper functions following TS 23.003 bit layout specification.
- Add helper functions for 5G-S-TMSI operations:
* nr_construct_5g_s_tmsi_part1: 5G-S-TMSI construction is defined
in 3GPP TS 23.003 and relevant at both gNB and UE side
* Add helper functions to be later used in NG Paging
* Adopt in NAS UE
* nr_extract_5g_s_tmsi_part1() - extract Part1 (39 bits) from full
* nr_extract_5g_s_tmsi_part2() - extract Part2 (9 bits) from full
* nr_build_full_5g_s_tmsi() - reconstruct full from Part1+Part2
* nr_deconstruct_5g_s_tmsi() - deconstruct into components
- Refactor manual bit manipulation to use helper functions:
* asn1_msg.c: use nr_extract_5g_s_tmsi_part1() in RRCSetupRequest
* asn1_msg.c: use nr_extract_5g_s_tmsi_part2() in RRCSetupComplete
* rrc_gNB.c: use nr_build_full_5g_s_tmsi() when reconstructing from parts
* rrc_gNB.c: use nr_deconstruct_5g_s_tmsi() when extracting components
- Optimize nr_construct_5g_s_tmsi_part1() to reuse extract function
There is no such thing as NG Register message, the naming is
inaccurate, however the goal of this commit is only to clarify that
and major refactoring is not yet carried out.
Move rrc_update_ue_pcell() from static function in rrc_gNB.c to public
function in rrc_cell_management.c, making it reusable across RRC code
paths. Replace duplicate PCell addition logic in handover paths
(intra-CU and inter-CU) and RRCSetup path with calls to this shared
function.
This eliminates code duplication between handover and RRCSetup paths,
centralizes PCell update logic (including cleanup of old PCell's DU
serving cells) in a single reusable function and makes the function
available for future use in other RRC procedures
Fix assertion failure in rrc_gNB_send_NGAP_NAS_FIRST_REQ() when RRC
Reestablishment falls back to RRC Setup. The fallback path was not
adding the PCell to the UE's serving_cells array, causing
rrc_get_pcell_for_ue() to return NULL.
Major changes:
- Add rrc_update_ue_pcell() helper function that handles PCell updates
for both new UEs (fallback) and existing UEs (normal reestablishment)
- Refactor normal reestablishment path to use rrc_update_ue_pcell()
helper instead of manual cleanup + add sequence
- Add PCell update to fallback_rrc_setup path using the same helper
- Move C-RNTI validation after current_cell fetch to ensure current_cell
is initialized before fallback_rrc_setup label
- Change error handling: return instead of fallback when PCell add fails
in normal reestablishment path
- Change gNB RRC enable_sdap default to true
- Update RRC and RUNMODEM docs to reflect new default behavior
- Clean up CI gNB configs by removing redundant enable_sdap=1
- Keep explicit SDAP disable config for NFAPI gNB VNF
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
A DRB To Modify Item contains a Flow Mapping Information,
which overrides previous mapping information. For consistency,
rename the count member to reflect a QoS Flow modification,
since it is not limited to setup only.
- Rename DRB flow mapping counters to `numQosFlowsMod`
for a DRB To Modify List
- Adjust encode/decode/equality + E1AP tests
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
- Delete drbs field from gNB_RrcConfigurationReq and its use in RCconfig_NRRRC()
- Remove GNB_CONFIG_STRING_DRBS, help text, index, and GNBPARAMS_CHECK entry from gnb_paramdef.h
- Drop DU-side verification and DRB count logging in gnb_config.c
Expand RRC developer and usage documentation to match the current
multi-cell design with separate DU and cell management.
- rrc-dev.md: Document DU and cell data structures and key functions
(get_du_by_assoc_id, get_cell_by_cell_id, rrc_add_cell_to_du, etc.);
add DU and cell lifecycle (F1 Setup, config update, disconnection)
and UE cell association (serving cells, PCell/SCells) with sequence
diagrams; add handover and cell association update flow; update UE
context description.
- rrc-usage.md: Update DU/cell list output format and description
(e.g. integrated DU-CU) and multi-cell per DU wording.
This commit adds documentation comments and logging to improve
code readability and debugging capabilities for the multi-cell
architecture.
Changes:
- gnb_config.c: Add logging when configuring DU with cell ID and PCI
- rrc_gNB_du.c: Add documentation comment for ssb_arfcn_mtc()
- rrc_gNB_du.c: Add documentation comment for dump_du_info()
After introduction of new cell management design, these helper functions
are now only used internally within their respective modules and do not
need to be part of the public API. They are made static and their
declarations are removed from public headers.
Changes:
- f1ap_interface_management.c: Make free_f1ap_cell() and
copy_f1ap_served_cell_info() static
- f1ap_interface_management.h: Remove declarations for the above functions
- rrc_gNB_du.c: Make get_dl_band() and get_ssb_scs() static
- rrc_gNB_du.h: Remove declarations for get_dl_band() and get_ssb_scs()
Remove the single-cell limit in F1 Setup Request processing and
refactor to loop-based cell handling. Move cell validation (PLMN
check, neighbor configuration validation, system info extraction),
cell creation, SIB encoding, and neighbor labeling inside a loop
over all available cells.
Update F1 Setup Response to include all cells instead of hardcoding to 1.
Add warning log when more than one cell is received. Add proper
cleanup with free_f1ap_setup_response() on error paths.
Impact:
- F1 Setup now accepts and processes multiple cells from a single
DU, enabling multi-cell deployments
- All cells are validated, created, and included in the setup
response
Finalize the migration from single-cell-per-DU to the multi-cell
architecture: remove legacy DU/cell fields and refactor RRC procedures
to use cell containers and UE serving cells instead of DU-based lookups.
Data structure changes:
- Remove nr_cellid from gNB_RRC_UE_t; cell identity comes from the UE's
serving_cells (PCell entry via ue_get_pcell_entry(ue)). UE_LOG_ARGS
and LOG_UE_* macros take a PCell entry pointer for null-safe cell_id
in logs; all call sites pass ue_get_pcell_entry(ue).
- Remove setup_req, mib, sib1, mtc from nr_rrc_du_container_t (held in
cell containers); remove nr_cellid from gNB_RRC_INST and its
assignment in gnb_config.c.
Function and signature updates:
- get_ssb_arfcn(): take cell container instead of DU.
- label_intra_frequency_neighbours(): drop du parameter, use cell only.
- Handover: Handover context (source and target) now stores cell
pointers (source->cell, target->cell) instead of DU pointers. When
the context is created (N2: on Handover Request; F1: in
nr_rrc_trigger_f1_ho), the target cell is set in ho_context->target->cell
and, for F1, the source cell in ho_context->source->cell.
nr_initiate_handover() takes only source_cell and reads the target
from ho_ctx->target->cell, so it no longer takes a target parameter.
The target is known at handover creation time, while the UE’s
serving_cells are only updated after F1 UE Context Setup Response.
- nr_rrc_trigger_f1_ho() and the N2 handover path pass cell pointers
and set ho_context->target->cell (and for F1, source->cell) when
the handover is triggered.
Procedure refactoring:
- Lookups: replace get_du_by_cell_id() with get_cell_by_cell_id()/
get_cell_by_pci(); remove get_du_by_cell_id() and
get_cell_information_by_phycellId().
Rationale: cell-specific data (MIB, SIB1, mtc, info) now lives in
cell containers, and a DU can host multiple cells. Callers need the
cell (to use cell->info, cell->mtc, etc.), not the DU. Looking up
by cell_id therefore returns the cell container
(get_cell_by_cell_id()); when the DU is needed, use
cell->assoc_id and get_du_by_assoc_id(). Looking up by PCI is
scoped (e.g. get_cell_by_pci_for_du() for a given DU, or via the
UE’s serving cells) because PCI is not globally unique.
- Setup/Reestablishment: resolve cell, register as PCell via
rrc_add_ue_serving_cell(); reestablishment resolves cell by PCI
(rrc_get_cell_by_pci_for_du), then rrc_remove_ue_scells_from_du +
rrc_add_ue_serving_cell; validate_ue_cell_association() after update.
- Measurement config: use cell->info (SCS/band) and cell->mtc.
- Handover: use cell containers end-to-end; after UE context
modification response call nr_rrc_update_cell_assoc_after_ho().
- NGAP: cell_id and TAC from UE PCell via rrc_get_pcell_for_ue();
Handover Notify: get cell for message content, use get_du_for_ue() for
DU existence check; paging resolves UE by 5G-S-TMSI-Part1 and uses that
UE's PCell (rrc_get_pcell_for_ue) for F1AP_PAGING_IND nr_cellid.
Performance and robustness:
- Use rrc_get_pcell_for_ue() when cell data is needed; use
get_du_for_ue() when only the DU is needed (F1/N2 HO trigger,
Handover Notify DU check) for efficiency.
- Reestablishment: remove old PCell before adding new; error handling
for PCell add and validation.
Code cleanup:
- F1 setup: stop copying/storing setup request in DU container; F1
disconnect only frees cell containers via rrc_free_cell_container().
- dump_du_info(): iterate du->cells and show all cells per DU.
- telnetsrv_ci.c: use du->gNB_DU_id directly and fix format (%ld).
- UeContextSetupRequest servCellIndex set to RRC_PCELL_INDEX; remove
servCellIndex from F1AP UE context modification request.
In rrc_gNB_NGAP.c, rrc_gNB_process_Handover_Request() is updated to
resolve the target by cell instead of by DU, then resolve the DU from
the cell's assoc_id. This aligns Handover Request with the new
cell-centric model and cell management APIs.
- Resolve target with get_cell_by_cell_id(&rrc->cells, msg->nr_cell_id)
instead of get_du_by_cell_id(); on failure, log "no cell found" and
send NGAP handover failure.
- Resolve DU with get_du_by_assoc_id(rrc, cell->assoc_id); add a
failure path (log, NGAP handover failure, return -1) when no DU
exists for the cell's assoc_id.
- Use cell->info (nr_rrc_cell_info_t) for logging and for key
derivation (nr_derive_key_ng_ran_star); use du->assoc_id
for UE context creation instead of du->setup_req->cell[0].info.
get_ssb_arfcn(du) is unchanged and still takes the DU; other DU-based
lookups are kept where still required.
Migrate F1 DU configuration update procedures in openair2/RRC/NR/rrc_gNB_du.c
to use the cell management API instead of accessing cell data through
setup_req, completing the transition to the new multi-cell architecture.
1. update_cell_info:
- Refactored to use cell management API: takes RRC instance, old cell_id,
and new cell info; finds cell via get_cell_by_cell_id() internally.
- Returns cell container pointer (or NULL on failure) instead of void.
- When cell_id changes: removes cell from RB tree (old key), updates via
cp_f1_served_cell_info_to_cell(), re-inserts (new key); validates no
duplicate cell_id/PCI before allowing change.
- Frees old MTC when new measurement timing config is present.
- Encapsulates cell lookup and update logic.
2. rrc_gNB_process_f1_du_configuration_update:
- Uses update_cell_info() for cell modify; validates cell belongs to DU
(assoc_id) after update.
- Duplicate checking via get_cell_by_cell_id() and
rrc_get_cell_by_pci_for_du()
- For cells to add: validates duplicate cell_id globally and duplicate
PCI within DU; rejects with logging.
- MIB/SIB1 updated in cell container (cell->mib, cell->sib1); uses
du->gNB_DU_id; passes cell to label_intra_frequency_neighbours();
removes direct setup_req->cell[0] access.
Backward compatibility: setup_req remains until migration is completed;
cell-specific data is managed in the cell container and accessed via
the cell management API. Improves separation of concerns and enables
proper multi-cell support.
Refactor F1 setup processing to create and manage cell containers during DU
initialization, establishing the foundation for multi-cell architecture where
cells are managed independently from DUs.
Why: Cell information is currently tied to F1AP structures (f1ap_served_cell_info_t),
which complicates multi-cell support. Introducing cell containers at F1 setup
decouples RRC cell management from F1AP and allows cells to be managed
independently while keeping existing code paths working.
Key changes:
1. Cell container creation (cp_f1_served_cell_info_to_cell):
New helper copying F1AP served cell info into nr_rrc_cell_container_t (cell_id,
pci, plmn, tac, TDD/FDD frequency info). Extracts and stores MTC in the cell.
2. Function signature updates:
get_cell_neighbour_list() and label_intra_frequency_neighbours() now take
nr_rrc_cell_container_t* and use cell->info; improved logging (cell_id, PCI,
SSB ARFCN).
3. valid_du_in_neighbour_configs:
Removed ssb_arfcn parameter; MTC is extracted and freed inside the function.
4. F1 Setup (rrc_gNB_process_f1_setup_req):
Initialize DU cell tree (RB_INIT(&du->cells)). Populate DU-only fields
(gNB_DU_id, gNB_DU_name, rrc_ver).
Flow:
- create cell with cp_f1_served_cell_info_to_cell
- add to global tree via rrc_add_cell()
- add DU via rrc_add_du()
- attach cell to DU with rrc_add_cell_to_du().
Store MIB/SIB1/MTC in cell.
Use cell container for neighbour labeling and SIB encoding.
5. Duplicate cell detection:
Use rrc_add_cell() for global cell tree insert; collision return indicates
duplicate cell_id. Clearer error messages for Cell ID vs PCI conflicts.
Use F1AP_CauseRadioNetwork_cell_not_available for cell conflicts.
6. DU configuration update:
Use get_cell_by_cell_id() to find cell, check assoc_id, pass cell container
to label_intra_frequency_neighbours().
7. DU disconnection:
Use rrc_cleanup_du() to remove cells from global tree and free resources;
logging uses DU fields (gNB_DU_id, gNB_DU_name).
8. Global cell tree:
Initialize rrc->cells in openair_rrc_gNB_configuration().
Backward compatibility: setup_req still built via cp_f1ap_setup_request();
du->mib, du->sib1, du->mtc remain set (shared with cell container).
Add integration tests for RRC cell and DU management and UE serving-cell
logic so that multi-cell behaviour and regressions can be validated
without running the full stack.
* test_du_lookup() – DU container lookup by assoc_id:
- Multiple DU creation and insertion into RRC DU tree
- Lookup of existing DUs by assoc_id
- Non-existing and invalid assoc_ids
- Cleanup of DU containers and cells
* test_cell_lookup() – Cell management and UE association:
- Cell lookup by cell_id and PCI (global and per-DU)
- DU-specific lookup: rrc_get_cell_for_du(), rrc_get_cell_by_pci_for_du()
- Duplicate cell and PCI collision handling (including PCI reuse across
DUs and rejection of duplicate PCI within same DU)
- Cell–DU association (add/remove cells from DU containers)
- UE serving cell: add PCell/SCells, get by ID, get PCell, max serving
cells limit, single PCell enforcement
- validate_ue_cell_association(), rrc_remove_ue_scells_from_du()
- Edge cases and error handling
Add openair2/RRC/NR/tests/rrc_cell_management_test.c and extend
openair2/RRC/NR/tests/CMakeLists.txt to build and register the test.
Add functions to manage UE serving cells so the RRC can track which cells
a UE is using (PCell and SCells) for multi-cell UE context and future
SCell management.
- rrc_cell_management.c / rrc_cell_management.h:
* rrc_get_ue_serving_cell_by_id(): return serving cell by servCellIndex
(O(k) linear search, k ≤ 32).
* rrc_add_ue_serving_cell(ue, cell, serving_cell_id): add entry to UE
serving_cells with validation: reject duplicate servCellIndex with
different nci, enforce max 32 serving cells (TS 38.331), keep PCell
at index 0 for O(1) access; return existing entry if same
servCellIndex and nci.
* rrc_remove_ue_scells_from_du(ue, assoc_id): remove all serving cells
for the given DU (handover/DU disconnect); use stored assoc_id for
O(k) comparison.
* ue_get_pcell_entry(): return PCell entry (first element, O(1)).
* rrc_get_pcell_for_ue(): return PCell container from cell tree using
UE's PCell entry.
* Header: RRC_PCELL_INDEX (0), RRC_MAX_NUM_SERVING_CELLS (32), and
declarations for the above.
- UE context lifecycle:
* rrc_gNB_create_ue_context(): seq_arr_init(serving_cells).
* rrc_delete_ue_data(): seq_arr_free(serving_cells).
Move DU tree management from rrc_gNB_du.c into rrc_cell_management so that
DU and cell lookup logic live in one place, improving maintainability and
testability (there is no DU lib).
- rrc_cell_management: add du_compare(), RB_GENERATE(rrc_du_tree),
get_du_by_assoc_id(), rrc_add_du(), rrc_rm_du(), rrc_cleanup_du(),
rrc_free_du_container(); declare them in rrc_cell_management.h.
- rrc_gNB_du: move du_compare(), RB_GENERATE, get_du_by_assoc_id()
to rrc_cell_management
This commit introduces a new library module (rrc_cell_management.c/h)
to centralise functions that provides cell lookup, DU-specific cell
management, and cell lifecycle managements.
The design uses a dual-tree architecture:
- Global cell tree: RB-tree at RRC level (rrc->cells) keyed by cell_id,
used for O(log N_CELL) lookups and for maintaining num_cells.
- DU-specific storage: seq_arr_t per DU (du->cells) for iteration and
management of cells belonging to each DU.
API added:
- Global tree: get_cell_by_cell_id()(finds cell using global RB-tree
lookup (O(log N_CELL) complexity); rrc_add_cell(); rrc_rm_cell()
(rrc_rm_cell removes from tree, decrements num_cells, and frees the
cell via rrc_free_cell_container).
- DU-local seq_arr: rrc_get_cell_for_du(), rrc_get_cell_by_pci_for_du(),
rrc_add_cell_to_du() (with duplicate cell_id/PCI checks).
- Cleanup: rrc_free_cell_container() (frees ASN.1 MIB/SIB1/MTC and
container
Build: add rrc_cell_management static library in openair2/RRC/NR;
link it into nr_rrc from top-level CMakeLists.txt.
Add foundational data structures in nr_rrc_defs.h for multi-cell handling
in RRC, separating DU management from cell management.
Design uses a global cell tree for O(log N) lookups while keeping cell
ownership in DUs for locality and maintenance.
The implementation maintains backward compatibility and follows the same
patterns as existing DU and CUUP management in the codebase, i.e. RB-trees
with logarithmic complexity for scalable multi-cell deployments.
- Cell container structures:
* nr_rrc_cell_container_t: cell-specific data (cell_id, pci, plmn, tac,
frequency info, mib, sib1, mtc)
* nr_rrc_cell_info_t: TDD/FDD modes; frequency structs nr_rrc_freq_info_t,
nr_rrc_tdd_info_t, nr_rrc_fdd_info_t
- UE serving cell tracking:
* ue_serving_cell_t: nci, serving_cell_id (ServCellIndex TS 38.331,
0=PCell, 1-31=SCell), assoc_id for fast DU lookup
* gNB_RRC_UE_t: seq_arr_t serving_cells, with PCell always being the
first in the sequence
- DU container refactoring:
* nr_rrc_du_container_t: DU-only fields (gNB_DU_id, gNB_DU_name, rrc_ver);
seq_arr_t cells for per-DU iteration; setup_req/mib/sib1/mtc kept for
backward compatibility
- Global cell tree:
* gNB_RRC_INST_s: RB_HEAD(rrc_cell_tree, nr_rrc_cell_container_t) cells,
num_cells (data only; lookup helpers get_cell_by_cell_id/get_cell_by_pci
to be added separately)
Neighbour lists are built per serving cell in fill_neighbour_cell_configuration.
Each neighbour in a list is identified by PCI; having two entries with the same
PCI in one cell's list would be ambiguous and indicate a configuration error.
This commit adds validation so that duplicate PCIs within a cell's neighbour
list are detected at configuration load time and cause a fatal assertion with
a clear error message.
Changes:
- Add eq_neighbour_pci() and get_neighbour_by_pci() using
common/utils/alg/find.h to look up a neighbour by PCI in a seq_arr.
- In fill_neighbour_cell_configuration(), before appending each
cell's neighbour list, iterate over neighbours and assert that no PCI
appears more than once
Replace generic UE event log with explicit INFO log including UE ID and RNTI
when removing a UE context and centralize access to UE fields via a local
pointer.
rrc_delete_ue_data removes the all the list in the UE context, including the
serving cells, and therefore the cell id should not be logged in the function
responsible for the removal of the UE context, which at this point is already
emptied and while the cells themselves are still there (in the DU/global cell
structures), the lists in the UE context are empty.
* Commit applies to Setup Request, CU/DU Configuration Update
* Set standard compliant max number of cells per DU
* Allocate large lists on the heap to prevent stack overflow
due to the large size
* Update relevant free functions
* Also, fix bug in eq_f1ap_cu_configuration_update
Also, improve comments in struct definition.
* 5G-S-TMSI construction is defined in 3GPP TS 23.003 and
relevant at both gNB and UE side
* Add helper functions to be later used in NG Paging
* Adopt in NAS UE
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.
However, the primary purpose of DL RRC MESSAGE TRANSFER is to deliver
the RRC message to the UE. The RRC message delivery is independent of
whether the old UE context can be retrieved. Per TS 38.473, the RRC
message must be delivered to the new UE regardless of old context
retrieval status.
Additionally, per TS 38.331 5.3.7.2 and 5.3.7.4, during reestablishment:
- The UE releases spCellConfig, which must be removed from CellGroupConfig
- SRB1 RLC must be reconfigured with specific parameters
These operations are required for the new UE during reestablishment and
are independent of whether the old UE context can be retrieved.
Fixes:
- Check if old UE context exists before accessing it
- If old UE does not exist, log error and clean up any stale F1 UE data,
but continue to deliver the RRC message
- Restructure code so context transfer only happens when oldUE exists
- Keep GTP-U update and RLC context transfer inside oldUE check (they
require old UE context to exist)
- Move spCellConfig handling and reestablish_rlc flag to execute
regardless during re-establishemnt (per TS 38.331 5.3.7.2)
- Move SRB1 RLC reconfiguration outside the oldUE check so it executes
regardless during re-establishment (per TS 38.331 5.3.7.4)
- Add function documentation and improve spec references in comments
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.
This field will be adopted to trigger cgc encoding at DU,
according to the specs (see subsequent commit for details).
Changes:
- Add gNB_DU_Configuration_Query field to f1ap_ue_context_mod_req_t
- Implement encoding/decoding
- Add to cp, eq, and free functions for the new field
- Update tests to include the new field
Issue: sometimes it happens that an ul failure occurs in the handover
pipeline, UE reconnects with different UE ID and fetch_du_by_ue_id fails.
- Modified fetch_du_by_ue_id in telnetsrv_ci.c to automatically find
the connected UE when no UE ID is provided, similar to other
telnet commands like rrc_gNB_trigger_f1_ho
- Updated test cases in container_sa_f1_ho_b210_quectel.xml to use
the improved command without hardcoded UE ID parameter
- This makes the command more robust and easier to use in CI tests
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.
Extract the common RRC container handling logic from
ue_context_setup_request() and ue_context_modification_request() into
a new static function handle_ue_context_rrc_container().
This refactoring:
- Eliminates code duplication between the two functions
- Centralizes RRC container forwarding logic
- Improves code maintainability and consistency
Extract common CellGroupConfig encoding logic from
ue_context_setup_request() and ue_context_modification_request() into
encode_cellgroup_config().
Replace uper_encode_to_buffer() with uper_encode_to_new_buffer() to:
- Remove 1024-byte buffer size limit
- Automatically allocate correct buffer size
- Simplify code (no manual bit-to-byte conversion)
- Align with other protocol encoders
- 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
When processing UL RRC messages from PDCP, the DU association ID (assoc_id)
was not being propagated to RRC, resulting in assoc_id being 0 in
rrc_gNB_decode_dcch.
Fix by setting originInstance in the ITTI message header to the stored
du_assoc_id from ue_data when PDCP creates the F1AP_UL_RRC_MESSAGE.
- 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
This commit adds support for the Handover Cancel initiating message
procedure code (NGAP_ProcedureCode_id_HandoverCancel).
Changes:
- ngap_gNB_decoder.c: Added case handler for Handover Cancel in
ngap_gNB_decode_initiating_message() to properly decode and log
incoming Handover Cancel messages from the AMF.
- ngap_gNB_encoder.c: Added Handover Cancel to the list of supported
initiating message procedure codes in ngap_gNB_encode_initiating(),
allowing the gNB to encode and send Handover Cancel messages.
The Handover Cancel procedure is already implemented in other parts of
the NGAP stack, these changes were missing to complete the support
by ensuring the procedure code is properly recognized in both the encoder
and decoder switch statements, following the same pattern as other
procedure codes.
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)
During N2 handover, the UE receives reconfigurationWithSync which correctly
sets the target cell frequency in mac->phy_config.config_req.carrier_config
via config_common_ue() call.
However, when SIB1 is decoded after reconfiguration,
nr_rrc_mac_config_req_sib1() calls config_common_ue_sa() which unconditionally
overwrites the frequency with the command-line parameter (downlink_frequency),
which corresponds to the source cell frequency.
This causes a critical issue during RRC re-establishment:
- The UE uses the wrong frequency (source cell) for key derivation (kgnb*)
- The gNB uses the correct frequency (target cell) for key derivation
- This mismatch results in different kgnb* keys on UE and gNB
- Integrity check fails: "Integrity of RRCReestablishment failed, going to IDLE"
Root cause:
config_common_ue_sa() is used for SIB1 processing (initial cell selection) and
uses ServingCellConfigCommonSIB which doesn't contain absoluteFrequencyPointA.
It must derive frequency from command-line parameters. However, after handover,
the frequency has already been correctly set by config_common_ue() (used for
reconfigurationWithSync) which uses ServingCellConfigCommon with absolute
frequency information.
Solution:
Modify config_common_ue_sa() to preserve the existing frequency if it's already
initialized (non-zero). Only set frequency from command-line parameters during
initial cell selection when dl_frequency is 0. This ensures:
- Initial cell selection: frequency derived from command-line parameter, just once
- After handover: frequency preserved from reconfigurationWithSync
- MAC maintains its own frequency state independently
The fix applies to both DL and UL frequencies to maintain consistency.
There is probably room for more refactoring to the resync flow, since
the functionalities in config_common_ue and config_common_ue_sa are
partially overlapping and upon reconfigurationWithSync some other
configurations might be applied twice.
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)