From 4b2cd156bb6557d9fe7c8becc34a227d138c9ad1 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 1 Apr 2025 15:42:36 +0200 Subject: [PATCH 01/26] Adopt existing ngap_ambr_t in NGAP PDU Session Setup Request --- openair2/COMMON/ngap_messages_types.h | 7 ++----- openair2/RRC/NR/rrc_gNB_NGAP.c | 2 +- openair3/NGAP/ngap_gNB_handlers.c | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 52cd919338..b899bb33e2 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -664,11 +664,8 @@ typedef struct ngap_pdusession_setup_req_s { /* E RAB setup request */ pdusession_t pdusession_setup_params[NGAP_MAX_PDU_SESSION]; - /* UE Uplink Aggregated Max Bitrates */ - uint64_t ueAggMaxBitRateUplink; - - /* UE Downlink Aggregated Max Bitrates */ - uint64_t ueAggMaxBitRateDownlink; + /* UE Aggregated Max Bitrates */ + ngap_ambr_t ueAggMaxBitRate; } ngap_pdusession_setup_req_t; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 82aa7b5a86..1ff31acae1 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -940,7 +940,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return; } - if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink)) { + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRate.br_dl)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE}; diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index ad8efce5a3..efa717e719 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -985,9 +985,9 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, true); asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL), - &msg->ueAggMaxBitRateUplink); + &msg->ueAggMaxBitRate.br_ul); asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &msg->ueAggMaxBitRateDownlink); + &msg->ueAggMaxBitRate.br_dl); NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListSUReq, true); From 615f5ef663c9624517c749f61b39061da3bc4c92 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 1 Apr 2025 15:45:36 +0200 Subject: [PATCH 02/26] Add decoding functions for common NGAP IEs and use in stack * Functions added: decode_ngap_guami decode_ngap_UEAggregateMaximumBitRate decode_ngap_nssai decode_ngap_security_capabilities decode_ngap_mobility_restriction * Adopt these functions in the common NGAP library --- openair3/NGAP/ngap_common.c | 48 ++++++++++++ openair3/NGAP/ngap_common.h | 5 ++ openair3/NGAP/ngap_gNB_handlers.c | 124 ++++++++---------------------- 3 files changed, 83 insertions(+), 94 deletions(-) diff --git a/openair3/NGAP/ngap_common.c b/openair3/NGAP/ngap_common.c index 385730f70d..7b960fed0b 100644 --- a/openair3/NGAP/ngap_common.c +++ b/openair3/NGAP/ngap_common.c @@ -28,6 +28,7 @@ */ #include +#include "conversions.h" #include "ngap_common.h" int asn1_xer_print = 0; @@ -66,3 +67,50 @@ void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in) break; } } + +nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in) +{ + nr_guami_t out = {0}; + TBCD_TO_MCC_MNC(&in->pLMNIdentity, out.mcc, out.mnc, out.mnc_len); + OCTET_STRING_TO_INT8(&in->aMFRegionID, out.amf_region_id); + OCTET_STRING_TO_INT16(&in->aMFSetID, out.amf_set_id); + OCTET_STRING_TO_INT8(&in->aMFPointer, out.amf_pointer); + return out; +} + +ngap_ambr_t decode_ngap_UEAggregateMaximumBitRate(const NGAP_UEAggregateMaximumBitRate_t *in) +{ + ngap_ambr_t ambr = {0}; + asn_INTEGER2ulong(&in->uEAggregateMaximumBitRateUL, &ambr.br_ul); + asn_INTEGER2ulong(&in->uEAggregateMaximumBitRateDL, &ambr.br_dl); + return ambr; +} + +nssai_t decode_ngap_nssai(const NGAP_S_NSSAI_t *in) +{ + nssai_t nssai = {0}; + OCTET_STRING_TO_INT8(&in->sST, nssai.sst); + if (in->sD != NULL) { + BUFFER_TO_INT24(in->sD->buf, nssai.sd); + } else { + nssai.sd = 0xffffff; + } + return nssai; +} + +ngap_security_capabilities_t decode_ngap_security_capabilities(const NGAP_UESecurityCapabilities_t *in) +{ + ngap_security_capabilities_t out = {0}; + out.nRencryption_algorithms = BIT_STRING_to_uint16(&in->nRencryptionAlgorithms); + out.nRintegrity_algorithms = BIT_STRING_to_uint16(&in->nRintegrityProtectionAlgorithms); + out.eUTRAencryption_algorithms = BIT_STRING_to_uint16(&in->eUTRAencryptionAlgorithms); + out.eUTRAintegrity_algorithms = BIT_STRING_to_uint16(&in->eUTRAintegrityProtectionAlgorithms); + return out; +} + +ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_MobilityRestrictionList_t *in) +{ + ngap_mobility_restriction_t out = {0}; + TBCD_TO_MCC_MNC(&in->servingPLMN, out.serving_plmn.mcc, out.serving_plmn.mnc, out.serving_plmn.mnc_digit_length); + return out; +} diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h index 259f0cbb18..82a8fe9234 100644 --- a/openair3/NGAP/ngap_common.h +++ b/openair3/NGAP/ngap_common.h @@ -85,6 +85,11 @@ extern int asn1_xer_print; typedef int (*ngap_message_decoded_callback)(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu); void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in); +nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in); +ngap_ambr_t decode_ngap_UEAggregateMaximumBitRate(const NGAP_UEAggregateMaximumBitRate_t *in); +nssai_t decode_ngap_nssai(const NGAP_S_NSSAI_t *in); +ngap_security_capabilities_t decode_ngap_security_capabilities(const NGAP_UESecurityCapabilities_t *in); +ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_MobilityRestrictionList_t *in); /** @}*/ diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index efa717e719..3f6b718861 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -747,30 +747,14 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 msg->gNB_ue_ngap_id = ue_desc_p->gNB_ue_ngap_id; msg->amf_ue_ngap_id = ue_desc_p->amf_ue_ngap_id; /* id-UEAggregateMaximumBitRate */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, false); - - if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL), - &(msg->ue_ambr.br_ul)); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &(msg->ue_ambr.br_dl)); - } else { - NGAP_WARN("could not find NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate\n"); + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, false); + if (ie != NULL) { + msg->ue_ambr = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); } - /* id-GUAMI */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_GUAMI, true); - - TBCD_TO_MCC_MNC(&ie->value.choice.GUAMI.pLMNIdentity, msg->guami.mcc, - msg->guami.mnc, msg->guami.mnc_len); - - msg->guami.amf_region_id = BIT_STRING_to_uint8(&ie->value.choice.GUAMI.aMFRegionID); - msg->guami.amf_set_id = BIT_STRING_to_uint16(&ie->value.choice.GUAMI.aMFSetID); - msg->guami.amf_pointer = BIT_STRING_to_uint8(&ie->value.choice.GUAMI.aMFPointer); - + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_GUAMI, true); + msg->guami = decode_ngap_guami(&ie->value.choice.GUAMI); NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListCxtReq, false); if (ie != NULL) { @@ -779,17 +763,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 for (i = 0; i < ie->value.choice.PDUSessionResourceSetupListCxtReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemCxtReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.array[i]; msg->pdusession_param[i].pdusession_id = item_p->pDUSessionID; - - OCTET_STRING_TO_INT8(&item_p->s_NSSAI.sST, msg->pdusession_param[i].nssai.sst); - if (item_p->s_NSSAI.sD != NULL) { - uint8_t *sd_p = (uint8_t *)&msg->pdusession_param[i].nssai.sd; - sd_p[0] = item_p->s_NSSAI.sD->buf[0]; - sd_p[1] = item_p->s_NSSAI.sD->buf[1]; - sd_p[2] = item_p->s_NSSAI.sD->buf[2]; - } else { - msg->pdusession_param[i].nssai.sd = 0xffffff; - } - + msg->pdusession_param[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); if (item_p->nAS_PDU) { msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); } @@ -799,62 +773,31 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 } /* id-AllowedNSSAI */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_AllowedNSSAI, true); - - //if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - NGAP_AllowedNSSAI_Item_t *allow_nssai_item_p = NULL; - - //NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); - //DevAssert(ie->value.choice.AllowedNSSAI.list.count > 0); - //DevAssert(ie->value.choice.AllowedNSSAI.list.count <= NGAP_maxnoofAllowedS_NSSAIs); - - AssertFatal(ie, "AllowedNSSAI not present, forging 2 NSSAI\n"); - - NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); - msg->nb_allowed_nssais = ie->value.choice.AllowedNSSAI.list.count; - - for(i = 0; i < ie->value.choice.AllowedNSSAI.list.count; i++) { - allow_nssai_item_p = ie->value.choice.AllowedNSSAI.list.array[i]; - - OCTET_STRING_TO_INT8(&allow_nssai_item_p->s_NSSAI.sST, msg->allowed_nssai[i].sst); - - if(allow_nssai_item_p->s_NSSAI.sD != NULL) { - msg->allowed_nssai[i].sd = 0; - BUFFER_TO_INT24((uint8_t *)allow_nssai_item_p->s_NSSAI.sD->buf, msg->allowed_nssai[i].sd); - } else { - msg->allowed_nssai[i].sd = 0xffffff; - } - } + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AllowedNSSAI, true); + NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); + msg->nb_allowed_nssais = ie->value.choice.AllowedNSSAI.list.count; + for (i = 0; i < ie->value.choice.AllowedNSSAI.list.count; i++) { + msg->allowed_nssai[i] = decode_ngap_nssai(&ie->value.choice.AllowedNSSAI.list.array[i]->s_NSSAI); + } /* id-UESecurityCapabilities */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true); + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true); + msg->security_capabilities = decode_ngap_security_capabilities(&ie->value.choice.UESecurityCapabilities); - msg->security_capabilities.nRencryption_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.nRencryptionAlgorithms); - msg->security_capabilities.nRintegrity_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.nRintegrityProtectionAlgorithms); - msg->security_capabilities.eUTRAencryption_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAencryptionAlgorithms); - msg->security_capabilities.eUTRAintegrity_algorithms = BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAintegrityProtectionAlgorithms); - - /* id-SecurityKey : Copy the security key */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityKey, true); - memcpy(&msg->security_key, ie->value.choice.SecurityKey.buf, ie->value.choice.SecurityKey.size); - - /* id-MobilityRestrictionList */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_MobilityRestrictionList, false); - - if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - NGAP_MobilityRestrictionList_t *mobility_rest_list_p = NULL; - mobility_rest_list_p = &ie->value.choice.MobilityRestrictionList; - - msg->mobility_restriction_flag = 1; - TBCD_TO_MCC_MNC( - &mobility_rest_list_p->servingPLMN, msg->mobility_restriction.serving_plmn.mcc, msg->mobility_restriction.serving_plmn.mnc, msg->mobility_restriction.serving_plmn.mnc_digit_length); - } + /* id-SecurityKey : Copy the security key */ + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityKey, true); + memcpy(&msg->security_key, ie->value.choice.SecurityKey.buf, ie->value.choice.SecurityKey.size); + /* id-MobilityRestrictionList */ + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_MobilityRestrictionList, + false); + if (ie != NULL) { + msg->mobility_restriction = decode_ngap_mobility_restriction(&ie->value.choice.MobilityRestrictionList); + msg->mobility_restriction_flag = true; + } /* id-NAS-PDU */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, @@ -984,10 +927,7 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 /* UE Aggregated Maximum Bitrate */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, true); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL), - &msg->ueAggMaxBitRate.br_ul); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &msg->ueAggMaxBitRate.br_dl); + msg->ueAggMaxBitRate = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListSUReq, true); @@ -999,12 +939,8 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 msg->pdusession_setup_params[i].pdusession_id = item_p->pDUSessionID; // S-NSSAI - OCTET_STRING_TO_INT8(&item_p->s_NSSAI.sST, msg->pdusession_setup_params[i].nssai.sst); - if (item_p->s_NSSAI.sD != NULL) { - BUFFER_TO_INT24((uint8_t *)item_p->s_NSSAI.sD->buf, msg->pdusession_setup_params[i].nssai.sd); - } else { - msg->pdusession_setup_params[i].nssai.sd = 0xffffff; - } + msg->pdusession_setup_params[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); From 5e2d7638d1e43cca1790c5e85bf87fe1863a506c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 12 Mar 2025 18:11:22 +0100 Subject: [PATCH 03/26] Move allocAddrCopy to NGAP utilities This function is needed also in upcoming NGAP libraries (i.e. N2 Handover) and therefore is moved to the NGAP utilities file. The function converts transport_layer_addr_t data struct to BIT_STRING_t by copying the content of its members. The naming is also updated to tnl_to_bitstring. --- openair3/NGAP/ngap_gNB_management_procedures.c | 12 ++++++++++++ openair3/NGAP/ngap_gNB_management_procedures.h | 3 +++ openair3/NGAP/ngap_gNB_nas_procedures.c | 14 ++------------ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_management_procedures.c b/openair3/NGAP/ngap_gNB_management_procedures.c index e82fd1401b..6ffce99d9c 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.c +++ b/openair3/NGAP/ngap_gNB_management_procedures.c @@ -39,6 +39,8 @@ #include "queue.h" #include "tree.h" #include "ds/byte_array.h" +#include "BIT_STRING.h" +#include "common/utils/utils.h" static ngap_gNB_internal_data_t ngap_gNB_internal_data; @@ -188,3 +190,13 @@ void ngap_gNB_remove_amf_desc(ngap_gNB_instance_t * instance) free(amf); } } + +void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in) +{ + if (in.length) { + out->buf = malloc_or_fail(in.length); + memcpy(out->buf, in.buffer, in.length); + out->size = in.length; + out->bits_unused = 0; + } +} diff --git a/openair3/NGAP/ngap_gNB_management_procedures.h b/openair3/NGAP/ngap_gNB_management_procedures.h index d71480da30..365fd0dd9d 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.h +++ b/openair3/NGAP/ngap_gNB_management_procedures.h @@ -29,6 +29,7 @@ */ #include "ds/byte_array.h" +#include "BIT_STRING.h" #ifndef NGAP_GNB_MANAGEMENT_PROCEDURES_H_ #define NGAP_GNB_MANAGEMENT_PROCEDURES_H_ @@ -47,4 +48,6 @@ uint16_t ngap_gNB_fetch_add_global_cnx_id(void); void ngap_gNB_prepare_internal_data(void); +void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in); + #endif /* NGAP_GNB_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 7729ffa4f2..10ef36ec2a 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -58,16 +58,6 @@ #include "s1ap_messages_types.h" #include "xer_encoder.h" -static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in) -{ - if (in.length) { - out->buf = malloc(in.length); - memcpy(out->buf, in.buffer, in.length); - out->size = in.length; - out->bits_unused = 0; - } -} - /** @brief Selects the AMF instance for a given UE based on identity information. * It attempts to select an AMF using the following prioritized criteria: * 1. GUAMI, if provided and valid (via Region ID, Set ID, Pointer). @@ -621,7 +611,7 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].gtp_teid, &tmp->gTP_TEID); - allocAddrCopy(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); + tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, @@ -936,7 +926,7 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID); - allocAddrCopy(&tmp->transportLayerAddress, pdusession->gNB_addr); + tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->gNB_addr); NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, tmp->transportLayerAddress.buf[0], From eb2facfa7613afa6c58764fb11bf28c04902033e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 16 May 2025 10:45:08 +0200 Subject: [PATCH 04/26] Add macro to iterate over seq_arr_t --- common/utils/ds/seq_arr.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/utils/ds/seq_arr.h b/common/utils/ds/seq_arr.h index 2fd049fa34..cb771405c5 100644 --- a/common/utils/ds/seq_arr.h +++ b/common/utils/ds/seq_arr.h @@ -34,6 +34,9 @@ SOFTWARE. #include #include +#define FOR_EACH_SEQ_ARR(type, var, arr) \ + for (type var = seq_arr_front(arr); var != seq_arr_end(arr); var = seq_arr_next(arr, var)) + typedef struct seq_arr_s { uint8_t* data; size_t size; From 1d2fb5af9dfe9cbade5314014a80b0bc71462930 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 29 Apr 2025 22:49:16 +0200 Subject: [PATCH 05/26] Fix FC value definition for NH (A.10 3GPP TS 33.501) --- openair3/SECU/key_nas_deriver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 20aba64e1e..1011eeb357 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -41,7 +41,7 @@ #include #define FC_KENB (0x11) -#define FC_NH (0x12) +#define FC_NH (0x6F) // A.10 3GPP TS 33.501 #define FC_KENB_STAR (0x13) /* 33401 #A.7 Algorithm for key derivation function. * This FC should be used for: From d06790fcf2ff7ec048b39071a6b04140cd55d99e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 29 Apr 2025 22:50:04 +0200 Subject: [PATCH 06/26] Move derive_kgnb to key_nas_deriver lib --- openair3/NAS/NR_UE/nr_nas_msg.c | 36 +-------------------------------- openair3/SECU/key_nas_deriver.c | 32 +++++++++++++++++++++++++++++ openair3/SECU/key_nas_deriver.h | 2 ++ 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index d152a5d4a3..4c5d6fb717 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -71,6 +71,7 @@ #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" #include "ds/byte_array.h" +#include "key_nas_deriver.h" #define MAX_NAS_UE 4 @@ -444,41 +445,6 @@ void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t memcpy(knas, out + 16, 16); } -static void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) -{ - /* Compute the KDF input parameter - * S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01 - */ - uint8_t input[32] = {0}; - // uint16_t length = 4; - // int offset = 0; - - LOG_TRACE(INFO, "%s with count= %d", __FUNCTION__, count); - memset(input, 0, 32); - input[0] = 0x6E; - // P0 - input[1] = count >> 24; - input[2] = (uint8_t)(count >> 16); - input[3] = (uint8_t)(count >> 8); - input[4] = (uint8_t)count; - // L0 - input[5] = 0; - input[6] = 4; - // P1 - input[7] = 0x01; - // L1 - input[8] = 0; - input[9] = 1; - - byte_array_t data = {.buf = input, .len = 10}; - kdf(kamf, data, 32, kgnb); - - printf("kgnb : "); - for (int pp = 0; pp < 32; pp++) - printf("%02x ", kgnb[pp]); - printf("\n"); -} - static void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) { uint8_t ak[6]; diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 1011eeb357..ec6da5e411 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -139,6 +139,38 @@ void nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t * NOTE: knas is dynamically allocated by the KDF function */ +/** @brief KgNB derivation (A.9 3GPP TS 33.501) */ +void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) +{ + /* Compute the KDF input parameter + * S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01 + */ + uint8_t input[32] = {0}; + + input[0] = 0x6E; + // P0 + input[1] = count >> 24; + input[2] = (uint8_t)(count >> 16); + input[3] = (uint8_t)(count >> 8); + input[4] = (uint8_t)count; + // L0 + input[5] = 0; + input[6] = 4; + // P1 + input[7] = 0x01; + // L1 + input[8] = 0; + input[9] = 1; + + byte_array_t data = {.buf = input, .len = 10}; + kdf(kamf, data, 32, kgnb); + + printf("kgnb : "); + for (int pp = 0; pp < 32; pp++) + printf("%02x ", kgnb[pp]); + printf("\n"); +} + void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB) { uint8_t s[7] = {0}; diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 4e84c5f3be..99c5b20b51 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -14,6 +14,8 @@ typedef enum { UP_INT_ALG = 0x06 } algorithm_type_dist_t; +void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb); + void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB); void derive_keNB_star(const uint8_t *kenb_32, From bd1f266ab5426ff39b8b7ca6f5e9d5e119527511 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 26 May 2025 16:26:26 +0200 Subject: [PATCH 07/26] Add utility to log hex buffer with size len (LOG_D) and remove unused legacy hex_dump * logging buffer is pretty useful for debugging purposes, e.g. derived key values --- common/utils/utils.c | 28 ------------------- common/utils/utils.h | 2 -- openair3/SECU/key_nas_deriver.c | 49 +++++++++++++++++++++------------ openair3/SECU/key_nas_deriver.h | 2 ++ 4 files changed, 33 insertions(+), 48 deletions(-) diff --git a/common/utils/utils.c b/common/utils/utils.c index 377c4512b7..33797b49df 100644 --- a/common/utils/utils.c +++ b/common/utils/utils.c @@ -7,34 +7,6 @@ #include #include "utils.h" - - -const char *hexdump(const void *data, size_t data_len, char *out, size_t out_len) -{ - char *p = out; - char *endp = out + out_len; - const uint8_t *q = data; - snprintf(p, endp - p, "[%zu]", data_len); - p += strlen(p); - for (size_t i = 0; i < data_len; ++i) - { - if (p >= endp) - { - static const char ellipses[] = "..."; - char *s = endp - sizeof(ellipses); - if (s >= p) - { - strcpy(s, ellipses); - } - break; - } - snprintf(p, endp - p, " %02X", *q++); - p += strlen(p); - } - return out; -} - - /**************************************************************************** ** ** ** Name: hex_char_to_hex_value() ** diff --git a/common/utils/utils.h b/common/utils/utils.h index 841cb2af9c..df188b812f 100644 --- a/common/utils/utils.h +++ b/common/utils/utils.h @@ -109,8 +109,6 @@ static inline void *malloc_or_fail(size_t size) #define PAGE_MASK 0xfffff000 #define virt_to_phys(x) (x) -const char *hexdump(const void *data, size_t data_len, char *out, size_t out_len); - // Converts an hexadecimal ASCII coded digit into its value. ** int hex_char_to_hex_value (char c); // Converts an hexadecimal ASCII coded string into its value.** diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index ec6da5e411..3c0b05dc50 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -57,14 +57,32 @@ #define NR_FC_ALG_KEY_DER (0x69) #define NR_FC_ALG_KEY_NG_RAN_STAR_DER (0x70) -// #define SECU_DEBUG 1 +static void log_hex_buffer(const char *label, const uint8_t *buf, const int len) +{ + char hex_str[len * 2 + 1]; + for (int i = 0; i < len; i++) { + snprintf(&hex_str[i * 2], 3, "%02x", buf[i]); + } + hex_str[len * 2] = '\0'; + LOG_D(UTIL, "%s: %s\n", label, hex_str); +} + +static const char* alg_type_to_str(algorithm_type_dist_t alg_type) +{ + switch (alg_type) { + case NAS_ENC_ALG: return "NAS_ENC_ALG"; + case NAS_INT_ALG: return "NAS_INT_ALG"; + case RRC_ENC_ALG: return "RRC_ENC_ALG"; + case RRC_INT_ALG: return "RRC_INT_ALG"; + case UP_ENC_ALG: return "UP_ENC_ALG"; + case UP_INT_ALG: return "UP_INT_ALG"; + default: return "UNKNOWN_ALG_TYPE"; + } +} static void derive_key_common(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t kasme[32], uint8_t FC, uint8_t out[32]) { uint8_t s[7]; -#if defined(SECU_DEBUG) - int i; -#endif /* FC */ s[0] = FC; @@ -83,18 +101,11 @@ static void derive_key_common(algorithm_type_dist_t alg_type, uint8_t alg_id, co s[5] = 0x00; s[6] = 0x01; -#if defined(SECU_DEBUG) - printf("%s FC %d nas_alg_type distinguisher %d nas_enc_alg_identity %d\n", __FUNCTION__, FC_ALG_KEY_DER, alg_type, alg_id); - - for (i = 0; i < 7; i ++) { - printf("0x%02x ", s[i]); - } - - printf("\n"); -#endif - byte_array_t data = {.len = 7, .buf = s}; kdf(kasme, data, 32, out); + log_hex_buffer("Input key (kgnb)", kasme, 32); + log_hex_buffer("Derivation string (s)", s, 7); + log_hex_buffer(alg_type_to_str(alg_type), out, 32); } /*! @@ -165,10 +176,9 @@ void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) byte_array_t data = {.buf = input, .len = 10}; kdf(kamf, data, 32, kgnb); - printf("kgnb : "); - for (int pp = 0; pp < 32; pp++) - printf("%02x ", kgnb[pp]); - printf("\n"); + log_hex_buffer("KAMF", kamf, 32); + log_hex_buffer("KDF input for kgnb", input, 10); + log_hex_buffer("Derived kgnb", kgnb, 32); } void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB) @@ -260,6 +270,9 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t byte_array_t data = {.buf = s, .len = 10}; const uint32_t len_key = 32; kdf(key, data, len_key, key_ng_ran_star); + log_hex_buffer("Input key", key, 32); + log_hex_buffer("KDF input for ng_ran*", s, 10); + log_hex_buffer("Derived key_ng_ran*", key_ng_ran_star, 32); } void derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB) diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 99c5b20b51..4cb336bce9 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -5,6 +5,8 @@ #include #include +#define SECURITY_KEY_LEN 32 + typedef enum { NAS_ENC_ALG = 0x01, NAS_INT_ALG = 0x02, From 70eb09dc099a13f60d9980a122ecb01730ce5c70 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 26 May 2025 16:28:45 +0200 Subject: [PATCH 08/26] Add NH derivation function (A.10 3GPP TS 33.501) --- openair3/SECU/key_nas_deriver.c | 24 ++++++++++++++++++++++++ openair3/SECU/key_nas_deriver.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 3c0b05dc50..a7cf27a1ff 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -293,3 +293,27 @@ void derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB byte_array_t data = {.buf = s, .len = 5}; kdf(keNB, data, 32, skgNB); } + +/** @brief NH derivation function (A.10 3GPP TS 33.501) + * @param k_amf: input key + * @param sync_input: pointer to the newly derived KgNB for the initial NH derivation, + * and the previous NH for all subsequent derivations + * @param nh: pointer to the derivated NH output */ +void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh) +{ + uint8_t s[SECURITY_KEY_LEN + 3] = {0}; + // FC + s[0] = FC_NH; + // P0 = SYNC-input + memcpy(&s[1], sync_input, SECURITY_KEY_LEN); + // L0 = length of SYNC-input (i.e. 0x00 0x20) + s[SECURITY_KEY_LEN + 1] = 0x00; + s[SECURITY_KEY_LEN + 2] = 0x20; + + byte_array_t data = {.buf = s, .len = sizeof(s)}; + kdf(k_amf, data, SECURITY_KEY_LEN, nh); + + log_hex_buffer("KDF input (SYNC string)", s, SECURITY_KEY_LEN + 3); + log_hex_buffer("Derived NH", nh, SECURITY_KEY_LEN); + +} diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 4cb336bce9..0ab14ad51a 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -34,4 +34,6 @@ void nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t key[32], uint8_t *key_ng_ran_star); +void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh); + #endif From 6de5b1d3debb2d47f8ad5463075981f1164b137f Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 7 Apr 2025 18:22:04 +0200 Subject: [PATCH 09/26] Store PCI received in reconfigurationWithSync According to 3GPP TS 38.331 5.3.5.5.2 (Reconfiguration with sync), the UE shall consider the target SpCell to be one with a physical cell identity indicated by the physCellId --- openair2/RRC/NR_UE/rrc_UE.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 4abc712507..bb58191e24 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1030,11 +1030,16 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, NR_Rec return; } - if (reconfigurationWithSync->spCellConfigCommon && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB) - rrc->arfcn_ssb = *reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB; + if (reconfigurationWithSync->spCellConfigCommon) { + /* if the frequencyInfoDL is included, consider the target SpCell + to be one on the SSB frequency indicated by the frequencyInfoDL */ + const NR_DownlinkConfigCommon_t *dcc = reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon; + if (dcc && dcc->frequencyInfoDL && dcc->frequencyInfoDL->absoluteFrequencySSB) + rrc->arfcn_ssb = *dcc->frequencyInfoDL->absoluteFrequencySSB; + + // consider the target SpCell to be one with a physical cell identity indicated by the physCellId + rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId; + } NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants; nr_timer_stop(&tac->T310); From de0730a4e82c4f48e54f40720c7a167a6fa78df8 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 11 Apr 2025 15:24:00 +0200 Subject: [PATCH 10/26] Use module_id in rrc_gNB_get_next_transaction_identifier call --- openair2/RRC/NR/rrc_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 78e472ed60..b8d37986cb 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2181,7 +2181,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance UE->ho_context->target->du_ue_id = resp->gNB_DU_ue_id; UE->ho_context->target->new_rnti = *resp->crnti; - uint8_t xid = rrc_gNB_get_next_transaction_identifier(0); + uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); UE->xids[xid] = RRC_DEDICATED_RECONF; uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; int size = rrc_gNB_encode_RRCReconfiguration(rrc, UE, xid, NULL, buffer, sizeof(buffer), true); From 9d951b109fff8c955dd96f11c7fc5622d5c64d75 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 26 May 2025 16:23:14 +0200 Subject: [PATCH 11/26] Return in nr_ue_get_sdu when mac->lc_ordered_list.count is 0 This count is used to size the dynamic array lcids_bj_pos. In case count is zero, this would lead to runtime error. With this change, the function will indicate to the caller that no SDUs are present and will print an error. --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 1922a3420e..b810bf8de6 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2703,6 +2703,10 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, mac->lc_ordered_list.count); // variable used to build the lcids with positive Bj + if (!mac->lc_ordered_list.count) { + LOG_E(NR_MAC, "Failed to init lcids_bj_pos: mac->lc_ordered_list.count = 0\n"); + return 0; + } nr_lcordered_info_t lcids_bj_pos[mac->lc_ordered_list.count]; int avail_lcids_count = select_logical_channels(mac, lcids_bj_pos); From eb4cd38577aabd6f8a8bea9014ebaef59dacb07b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 12 Mar 2025 14:53:20 +0100 Subject: [PATCH 12/26] Refactor handling of NGAP UE Context in ngap_gNB_handle_nas_first_req this commit is refactoring the function ngap_gNB_handle_nas_first_req to (1) fill first a local instance of ngap_gNB_ue_context_t and then (2) pass it to ngap_store_ue_context which will allocate memory for the instance to store in ngap --- openair3/NGAP/ngap_gNB_nas_procedures.c | 31 +++++++++++++------------ openair3/NGAP/ngap_gNB_ue_context.c | 5 +++- openair3/NGAP/ngap_gNB_ue_context.h | 2 +- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 10ef36ec2a..74130e75f8 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -165,16 +165,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf head->value.present = NGAP_InitiatingMessage__value_PR_InitialUEMessage; NGAP_InitialUEMessage_t *out = &head->value.choice.InitialUEMessage; - /* Store the UE context in NGAP with: - * selected AMF, selected PLMN identity, gNB ID - * the unique gNB UE NGAP ID, used for the duration of the connectivity */ - struct ngap_gNB_ue_context_s *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p)); - DevAssert(ue_desc_p != NULL); - ue_desc_p->amf_ref = amf; - ue_desc_p->gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id; - ue_desc_p->gNB_instance = instance_p; - ue_desc_p->selected_plmn_identity = UEfirstReq->plmn; - ngap_store_ue_context(ue_desc_p); + /* Create and store NGAP UE context */ + ngap_gNB_ue_context_t ue_desc_p = { + .amf_ref = amf, + .gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id, + .gNB_instance = instance_p, + .selected_plmn_identity = UEfirstReq->plmn, + }; // RAN UE NGAP ID (M) { @@ -182,7 +179,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_RAN_UE_NGAP_ID; - ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p->gNB_ue_ngap_id; + ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p.gNB_ue_ngap_id; } /* NAS-PDU (M): transferred transparently */ @@ -208,7 +205,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - plmn_id_t *plmn = &ue_desc_p->selected_plmn_identity; + plmn_id_t *plmn = &ue_desc_p.selected_plmn_identity; MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); /* In case of network sharing, @@ -255,7 +252,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf DevMessage("Failed to encode initial UE message\n"); /* Update the current NGAP UE state */ - ue_desc_p->ue_state = NGAP_UE_WAITING_CSR; + ue_desc_p.ue_state = NGAP_UE_WAITING_CSR; /* Assign a stream for this UE : * From 3GPP 38.412 7)Transport layers: * Within the SCTP association established between one AMF and gNB pair: @@ -272,9 +269,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf if ((amf->nextstream == 0) && (amf->out_streams > 1)) { amf->nextstream += 1; } - ue_desc_p->tx_stream = amf->nextstream; + ue_desc_p.tx_stream = amf->nextstream; + + /* Create and store UE context */ + ngap_store_ue_context(&ue_desc_p); + /* Send encoded message over sctp */ - ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p->tx_stream); + ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p.tx_stream); return 0; } diff --git a/openair3/NGAP/ngap_gNB_ue_context.c b/openair3/NGAP/ngap_gNB_ue_context.c index c4b7b012ef..d0949b88c2 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.c +++ b/openair3/NGAP/ngap_gNB_ue_context.c @@ -60,8 +60,11 @@ static int ngap_gNB_compare_gNB_ue_ngap_id(struct ngap_gNB_ue_context_s *p1, str RB_GENERATE(ngap_ue_map, ngap_gNB_ue_context_s, entries, ngap_gNB_compare_gNB_ue_ngap_id); -void ngap_store_ue_context(struct ngap_gNB_ue_context_s *ue_desc_p) +void ngap_store_ue_context(const ngap_gNB_ue_context_t *ue) { + LOG_I(NGAP, "Create UE context (ID %d) for AMF '%s' (assoc_id %d)\n", ue->gNB_ue_ngap_id, ue->amf_ref->amf_name, ue->amf_ref->assoc_id); + ngap_gNB_ue_context_t *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p)); + *ue_desc_p = *ue; if (RB_INSERT(ngap_ue_map, &ngap_ue_head, ue_desc_p)) LOG_E(NGAP, "Bug in UE uniq number allocation %u, we try to add a existing UE\n", ue_desc_p->gNB_ue_ngap_id); return; diff --git a/openair3/NGAP/ngap_gNB_ue_context.h b/openair3/NGAP/ngap_gNB_ue_context.h index 4c0c63239f..aaf9e83bbc 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.h +++ b/openair3/NGAP/ngap_gNB_ue_context.h @@ -78,7 +78,7 @@ typedef struct ngap_gNB_ue_context_s { ngap_gNB_instance_t *gNB_instance; } ngap_gNB_ue_context_t; -void ngap_store_ue_context(ngap_gNB_ue_context_t *ue_desc_p); +void ngap_store_ue_context(const ngap_gNB_ue_context_t *ue_desc_p); ngap_gNB_ue_context_t *ngap_get_ue_context(uint32_t gNB_ue_ngap_id); ngap_gNB_ue_context_t *ngap_detach_ue_context(uint32_t gNB_ue_ngap_id); From 63b4a784a8913bb7df369c77d9f02a4658c985db Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 12 Mar 2025 16:10:36 +0100 Subject: [PATCH 13/26] Use byte_array_t in nr_initiate_handover --- openair2/RRC/NR/rrc_gNB_mobility.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index e6e50ffbf1..c1ab2862fe 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -73,8 +73,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, const nr_rrc_du_container_t *source_du, const nr_rrc_du_container_t *target_du, - uint8_t *ho_prep_buf, - uint32_t ho_prep_len, + byte_array_t *ho_prep_info, ho_req_ack_t ack, ho_success_t success, ho_cancel_t cancel) @@ -83,7 +82,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, DevAssert(ue != NULL); DevAssert(target_du != NULL); // source_du might be NULL -> inter-CU handover - DevAssert(ho_prep_buf != NULL && ho_prep_len > 0); + DevAssert(ho_prep_info->buf != NULL && ho_prep_info->len > 0); if (ue->ho_context != NULL) { LOG_E(NR_RRC, "handover for UE %u ongoing, cannot trigger new\n", ue->rrc_ue_id); @@ -130,8 +129,8 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, target_du->setup_req->cell[0].info.nr_pci); cu_to_du_rrc_information_t cu2du = { - .handoverPreparationInfo = ho_prep_buf, - .handoverPreparationInfo_length = ho_prep_len, + .handoverPreparationInfo = ho_prep_info->buf, + .handoverPreparationInfo_length = ho_prep_info->len, }; f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE] = {0}; @@ -327,7 +326,8 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain ho_req_ack_t ack = nr_rrc_f1_ho_acknowledge; ho_success_t success = nr_rrc_f1_ho_complete; ho_cancel_t cancel = nr_rrc_cancel_f1_ho; - nr_initiate_handover(rrc, ue, source_du, target_du, buf, size, ack, success, cancel); + byte_array_t hpi = {.buf = buf, .len = size}; + nr_initiate_handover(rrc, ue, source_du, target_du, &hpi, ack, success, cancel); } void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue) From 75c7220345679c18eab0ce6d42c15de1874fa69f Mon Sep 17 00:00:00 2001 From: batuhan duyuler Date: Fri, 7 Mar 2025 12:14:05 +0100 Subject: [PATCH 14/26] Refactored code to populate DRBs to be setup list in nr_initiate_handover Co-authored-by: Guido Casati --- openair2/RRC/NR/rrc_gNB_mobility.c | 75 ++++++++++++++++-------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index c1ab2862fe..54c0f6f17d 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -61,6 +61,46 @@ static void free_ho_ctx(nr_handover_context_t *ho_ctx) free(ho_ctx); } +static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE]) +{ + int nb_drb = 0; + for (int i = 0; i < MAX_DRBS_PER_UE; ++i) { + drb_t *rrc_drb = &ue->established_drbs[i]; + if (rrc_drb->status == DRB_INACTIVE) + continue; + + f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; + nb_drb++; + drb->drb_id = rrc_drb->drb_id; + drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; + memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; + drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid; + drb->up_ul_tnl_length = 1; + + /* fetch an existing PDU session for this DRB */ + rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb->drb_id); + AssertFatal(pdu != NULL, "no PDU session for DRB ID %ld\n", drb->drb_id); + drb->nssai = pdu->param.nssai; + + // for the moment, we only support one QoS flow. Put a reminder in case + // this changes + AssertFatal(pdu->param.nb_qos == 1, "only 1 Qos flow supported\n"); + drb->drb_info.flows_to_be_setup_length = 1; + drb->drb_info.flows_mapped_to_drb = calloc_or_fail(1, sizeof(drb->drb_info.flows_mapped_to_drb[0])); + AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); + int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0]; + DevAssert(qfi > 0); + drb->drb_info.flows_mapped_to_drb[0].qfi = qfi; + pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(qfi, pdu); + drb->drb_info.flows_mapped_to_drb[0].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char); + + /* the DRB QoS parameters: we just reuse the ones from the first flow */ + drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; + } + return nb_drb; +} + /* \brief Initiate a handover of UE to a specific target cell handled by this * CU. * \param ue a UE context for which the handover should be triggered. The UE @@ -134,40 +174,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, }; f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE] = {0}; - int nb_drb = 0; - for (int i = 0; i < sizeofArray(drbs); ++i) { - drb_t *rrc_drb = &ue->established_drbs[i]; - if (rrc_drb->status == DRB_INACTIVE) - continue; - - f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; - nb_drb++; - drb->drb_id = rrc_drb->drb_id; - drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; - memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid; - drb->up_ul_tnl_length = 1; - - /* fetch an existing PDU session for this DRB */ - rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb->drb_id); - AssertFatal(pdu != NULL, "no PDU session for DRB ID %ld\n", drb->drb_id); - drb->nssai = pdu->param.nssai; - - // for the moment, we only support one QoS flow. Put a reminder in case - // this changes - AssertFatal(pdu->param.nb_qos == 1, "only 1 Qos flow supported\n"); - drb->drb_info.flows_to_be_setup_length = 1; - drb->drb_info.flows_mapped_to_drb = calloc_or_fail(1, sizeof(f1ap_flows_mapped_to_drb_t)); - int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0]; - DevAssert(qfi > 0); - drb->drb_info.flows_mapped_to_drb[0].qfi = qfi; - pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(qfi, pdu); - drb->drb_info.flows_mapped_to_drb[0].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char); - - /* the DRB QoS parameters: we just reuse the ones from the first flow */ - drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; - } + int nb_drb = fill_drb_to_be_setup(rrc, ue, drbs); f1ap_srb_to_be_setup_t srbs[2] = {{.srb_id = 1, .lcid = 1}, {.srb_id = 2, .lcid = 2}}; f1ap_served_cell_info_t *cell_info = &target_du->setup_req->cell[0].info; From d413cf969651001dacea43ddca47c3f55a1bfa73 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 16 May 2025 10:44:11 +0200 Subject: [PATCH 15/26] Refactor handover functions: get_neighbour_cell_information and get_neighbour_config * differentiate the 2 functions based on the input: either NR Cell ID or PCI * enhanced variables naming to distinguish the parameters * add logging for debugging purposes --- openair2/RRC/NR/rrc_gNB.c | 77 ++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b8d37986cb..b924bfd0d0 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -96,6 +96,7 @@ #include "E1AP/lib/e1ap_interface_management.h" #include "NR_DL-DCCH-Message.h" #include "ds/byte_array.h" +#include "alg/find.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -130,39 +131,47 @@ static void freeDRBlist(NR_DRB_ToAddModList_t *list) return; } -const neighbour_cell_configuration_t *get_neighbour_config(int serving_cell_nr_cellid) +static bool eq_cell_id(const void *vval, const void *vit) { - const gNB_RRC_INST *rrc = RC.nrrrc[0]; - seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration; - if (!neighbour_cell_configuration) - return NULL; + const int *cell_id = (const int *)vval; + const neighbour_cell_configuration_t *cell = (const neighbour_cell_configuration_t *)vit; + return cell->nr_cell_id == *cell_id; +} - for (int cellIdx = 0; cellIdx < neighbour_cell_configuration->size; cellIdx++) { - neighbour_cell_configuration_t *neighbour_config = - (neighbour_cell_configuration_t *)seq_arr_at(neighbour_cell_configuration, cellIdx); - if (neighbour_config->nr_cell_id == serving_cell_nr_cellid) - return neighbour_config; +const neighbour_cell_configuration_t *get_neighbour_cell_config(const gNB_RRC_INST *rrc, int cell_id) +{ + if (!rrc->neighbour_cell_configuration) + return NULL; + seq_arr_t *head = rrc->neighbour_cell_configuration; + LOG_D(NR_RRC, "Number of neighbour cell configurations: %ld\n", head->size); + elm_arr_t e = find_if(head, &cell_id, eq_cell_id); + if (e.found) { + const neighbour_cell_configuration_t *cell = (const neighbour_cell_configuration_t *)e.it; + LOG_D(NR_RRC, "Found matching neighbour cell with Cell ID %ld\n", cell->nr_cell_id); + return cell; } return NULL; } -const nr_neighbour_gnb_configuration_t *get_neighbour_cell_information(int serving_cell_nr_cellid, int neighbour_cell_phy_id) +static bool eq_pci(const void *vval, const void *vit) { - const gNB_RRC_INST *rrc = RC.nrrrc[0]; - seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration; - for (int cellIdx = 0; cellIdx < neighbour_cell_configuration->size; cellIdx++) { - neighbour_cell_configuration_t *neighbour_config = - (neighbour_cell_configuration_t *)seq_arr_at(neighbour_cell_configuration, cellIdx); - if (!neighbour_config) - continue; + const int *pci = (const int *)vval; + const nr_neighbour_gnb_configuration_t *neighbour = (const nr_neighbour_gnb_configuration_t *)vit; + return neighbour->physicalCellId == *pci; +} - for (int neighbourIdx = 0; neighbourIdx < neighbour_config->neighbour_cells->size; neighbourIdx++) { - nr_neighbour_gnb_configuration_t *neighbour = - (nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbour_config->neighbour_cells, neighbourIdx); - if (neighbour != NULL && neighbour->physicalCellId == neighbour_cell_phy_id) - return neighbour; - } +const nr_neighbour_gnb_configuration_t *get_neighbour_gnb_by_pci(const neighbour_cell_configuration_t *cell, int pci) +{ + seq_arr_t *head = cell->neighbour_cells; + DevAssert(head != NULL); + LOG_D(NR_RRC, "Number of neighbour cells: %ld\n", head->size); + elm_arr_t e = find_if(head, &pci, eq_pci); + if (e.found) { + const nr_neighbour_gnb_configuration_t *neighbour = (const nr_neighbour_gnb_configuration_t *)e.it; + LOG_D(NR_RRC, "Found matching neighbour cell with PCI %d and Cell ID %ld\n", neighbour->physicalCellId, neighbour->nrcell_id); + return neighbour; } + LOG_E(NR_RRC, "No matching neighbour cell found for Physical Cell ID: %d\n", pci); return NULL; } @@ -564,7 +573,7 @@ static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, int band = get_dl_band(cell_info); const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; const NR_MeasTiming_t *mt = mtlist->list.array[0]; - const neighbour_cell_configuration_t *neighbour_config = get_neighbour_config(cell_info->nr_cellid); + const neighbour_cell_configuration_t *neighbour_config = get_neighbour_cell_config(rrc, cell_info->nr_cellid); seq_arr_t *neighbour_cells = NULL; if (neighbour_config) neighbour_cells = neighbour_config->neighbour_cells; @@ -1391,7 +1400,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, int servingCellRSRP = 0; int neighbourCellRSRP = 0; - int servingCellId = -1; + int scell_pci = -1; switch (event_triggered->eventId.present) { case NR_EventTriggerConfig__eventId_PR_eventA2: @@ -1408,7 +1417,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) { const NR_MeasResultServMO_t *meas_result_serv_MO = measResults->measResultServingMOList.list.array[serving_cell_idx]; - servingCellId = *(meas_result_serv_MO->measResultServingCell.physCellId); + scell_pci = *(meas_result_serv_MO->measResultServingCell.physCellId); if (meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsSSB_Cell) { servingCellRSRP = *(meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsSSB_Cell->rsrp) - 157; } else { @@ -1426,7 +1435,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, const NR_MeasResultListNR_t *measResultListNR = measResults->measResultNeighCells->choice.measResultListNR; for (int neigh_meas_idx = 0; neigh_meas_idx < measResultListNR->list.count; neigh_meas_idx++) { const NR_MeasResultNR_t *meas_result_neigh_cell = (measResultListNR->list.array[neigh_meas_idx]); - const int neighbourCellId = *(meas_result_neigh_cell->physCellId); + const int neighbour_pci = *(meas_result_neigh_cell->physCellId); // TS 138 133 Table 10.1.6.1-1: SS-RSRP and CSI-RSRP measurement report mapping const struct NR_MeasResultNR__measResult__cellResults *cellResults = &(meas_result_neigh_cell->measResult.cellResults); @@ -1439,13 +1448,13 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, LOG_I(NR_RRC, "HO LOG: Measurement Report for the neighbour %d with RSRP: %d\n", - neighbourCellId, + neighbour_pci, neighbourCellRSRP); - const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbourCellId); - const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(servingCellId); - const nr_neighbour_gnb_configuration_t *neighbour = - get_neighbour_cell_information(serving_cell->nr_cellid, neighbourCellId); + const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbour_pci); + const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(scell_pci); + const neighbour_cell_configuration_t *cell = get_neighbour_cell_config(rrc, serving_cell->nr_cellid); + const nr_neighbour_gnb_configuration_t *neighbour = get_neighbour_gnb_by_pci(cell, neighbour_pci); // CU does not have f1 connection with neighbour cell context. So check does serving cell has this phyCellId as a // neighbour. if (!neigh_cell && neighbour) { @@ -1465,7 +1474,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, nr_rrc_du_container_t *target_du = get_du_by_cell_id(rrc, neigh_cell->nr_cellid); nr_rrc_trigger_f1_ho(rrc, ue, source_du, target_du); } else { - LOG_W(NR_RRC, "UE %d: received A3 event for stronger neighbor PCI %d, but no such neighbour in configuration\n", ue->rrc_ue_id, neighbourCellId); + LOG_W(NR_RRC, "UE %d: received A3 event for stronger neighbor PCI %d, but no such neighbour in configuration\n", ue->rrc_ue_id, neighbour_pci); } } From a937eaec234ec05d20d9f383f31bbcd98b0ac3c7 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 25 Feb 2025 17:15:16 +0100 Subject: [PATCH 16/26] Rework RRCReconfiguration handling in RRC/ASN1 according to TS 38.331, RRCReconfiguration messages can be carried in a container by different RRC messages, e.g. HandoverPreparationInformation, HandoverCommand, RRCResume etc.. therefore before the introduction of new RRCReconfiguration messages, e.g. for handover, a new design seems to be necessary in order to improve modularity and maintainability of the code. The goal of this commit is to make the generation of RRCReconfiguration messages more modular by (1) preparing the RRCReconfiguration parameters data in RRC (2) pass it to ASN1 for IEs allocation (3) encode to buffer The following changes are introduced: (1) introduce struct nr_rrc_reconfig_param_t to store the RRC parameters relevant to encode the RRCReconfiguration IEs (2) add RRC function get_RRCReconfiguration_params to fetch nr_rrc_reconfig_param_t data from the UE context and (3) pass it to the ASN1 encoder, e.g. do_RRCReconfiguration (4) add a function build_RRCReconfiguration_IEs to allocate memory and build the ASN1 NR_RRCReconfiguration_IEs_t and (5) adopt it in do_RRCReconfiguration (4) add free_RRCReconfiguration_params for memory management of nr_rrc_reconfig_param_t data (6) add test for rrc_reconfiguration get_RRCReconfiguration_params: This function prepares RRCReconfigurationParams for RRC encoding. Motivation of this change: depending on the RRCReconfiguration message to be encoded, the ownership of ASN1 memory allocation should belong to the ASN1 layer, therefore this function is preparing the nr_rrc_reconfig_param_t data to pass to the ASN1 encoder to build the ASN1 message and encode to buffer The function is preparing the params for the IEs that are either mandatory or shared among different RRC messages. Specific fields that depend on the message to be encoded are then added afterwards in the caller. The input param to indicate re-establishment has been split between SRBs and DRBs, since depending on the scenario the PDCP re-establishment can vary. This will be addressed in a later commit. This function is also handling xid. build_RRCReconfiguration_IE: The long term goal is to transfer ownership of memory allocation in ASN1 encoding to build_RRCReconfiguration_IE, then by calling ASN_STRUCT_FREE_CONTENTS_ONLY on dl_dcch_msg, all IEs allocated in the context are freed after encoding to buffer. In the long term, createDRBlist, createSRBlist can also be brought into the context of build_RRCReconfiguration_IEs and free the ASN1 structure after encoding. This improves maintability and helps preventing memory leaks. Currently, what is not allocated in the context, is nulled and freed outside. free_RRCReconfiguration_params: this function frees memory allocated to build the nr_rrc_reconfig_param_t data, including the NR_DRB_ToAddModList_t and NR_SRB_ToAddModList_t. The function freeDRBlist has been removed since no longer necessary. dedicated_NAS_msg_list: dedicated_NAS_msg_list handling has also been refactored, by: (1) fetch the NAS PDUs from the UE context in get_RRCReconfiguration_params, which translates to (2) passing an array of dedicatedNAS-MessageList + size to the ASN1 encoding function where (3) the ASN1 encoding logic for the dedicated_NAS_msg_list IE has been moved Note, 3GPP TS 38.331: dedicatedNAS-MessageList: SEQUENCE (SIZE(1..maxDRB)) OF DedicatedNAS-Message --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 183 ++++++----- openair2/RRC/NR/MESSAGES/asn1_msg.h | 28 +- .../RRC/NR/MESSAGES/tests/test_asn1_msg.cpp | 79 +++++ openair2/RRC/NR/nr_rrc_proto.h | 3 + openair2/RRC/NR/rrc_gNB.c | 288 ++++++++---------- 5 files changed, 315 insertions(+), 266 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 6a7ee77b52..6ab4ffc2fc 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -143,6 +143,7 @@ #include "common/ran_context.h" #include "conversions.h" +#include "ds/byte_array.h" //#define XER_PRINT @@ -499,112 +500,108 @@ int do_NR_RRCRelease(uint8_t *buffer, size_t buffer_size, uint8_t Transaction_id return((enc_rval.encoded+7)/8); } -//------------------------------------------------------------------------------ -int do_RRCReconfiguration(int rrc_ue_id, - uint8_t *buffer, - size_t buffer_size, - uint8_t Transaction_id, - NR_SRB_ToAddModList_t *SRB_configList, - NR_DRB_ToAddModList_t *DRB_configList, - NR_DRB_ToReleaseList_t *DRB_releaseList, - NR_SecurityConfig_t *security_config, - NR_MeasConfig_t *meas_config, - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList, - NR_CellGroupConfig_t *cellGroupConfig) -//------------------------------------------------------------------------------ +/** @brief Build RRCReconfiguration message (3GPP TS 38.331) */ +static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_reconfig_param_t *params) { - NR_DL_DCCH_Message_t dl_dcch_msg={0}; - asn_enc_rval_t enc_rval; - NR_RRCReconfiguration_IEs_t *ie; + NR_RRCReconfiguration_IEs_t *ie = calloc_or_fail(1, sizeof(*ie)); - dl_dcch_msg.message.present = NR_DL_DCCH_MessageType_PR_c1; - asn1cCalloc(dl_dcch_msg.message.choice.c1, c1);// = CALLOC(1, sizeof(struct NR_DL_DCCH_MessageType__c1)); - c1->present = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; + // radioBearerConfig + if ((params->srb_config_list && params->srb_config_list->list.size) + || (params->drb_config_list && params->drb_config_list->list.size)) { + ie->radioBearerConfig = calloc_or_fail(1, sizeof(*ie->radioBearerConfig)); + struct NR_RadioBearerConfig *cfg = ie->radioBearerConfig; + cfg->srb_ToAddModList = params->srb_config_list; + cfg->drb_ToAddModList = params->drb_config_list; + cfg->securityConfig = params->security_config; + cfg->srb3_ToRelease = NULL; + cfg->drb_ToReleaseList = params->drb_release_list; + } - asn1cCalloc(c1->choice.rrcReconfiguration, rrcReconf); // = calloc(1, sizeof(NR_RRCReconfiguration_t)); - rrcReconf->rrc_TransactionIdentifier = Transaction_id; - rrcReconf->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; + /* measConfig */ + ie->measConfig = params->meas_config; - /******************** Radio Bearer Config ********************/ - /* Configure Security */ - // security_config = CALLOC(1, sizeof(NR_SecurityConfig_t)); - // security_config->securityAlgorithmConfig = CALLOC(1, sizeof(*ie->radioBearerConfig->securityConfig->securityAlgorithmConfig)); - // security_config->securityAlgorithmConfig->cipheringAlgorithm = NR_CipheringAlgorithm_nea0; - // security_config->securityAlgorithmConfig->integrityProtAlgorithm = NULL; - // security_config->keyToUse = CALLOC(1, sizeof(*ie->radioBearerConfig->securityConfig->keyToUse)); - // *security_config->keyToUse = NR_SecurityConfig__keyToUse_master; + /* nonCriticalExtension, RRCReconfiguration-v1530-IEs */ + if (params->cell_group_config || params->num_nas_msg) { + // Allocate memory for extension IE + ie->nonCriticalExtension = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension)); + } - ie = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t)); - if ((SRB_configList && SRB_configList->list.size) || - (DRB_configList && DRB_configList->list.size)) { - ie->radioBearerConfig = calloc(1, sizeof(NR_RadioBearerConfig_t)); - ie->radioBearerConfig->srb_ToAddModList = SRB_configList; - ie->radioBearerConfig->drb_ToAddModList = DRB_configList; - ie->radioBearerConfig->securityConfig = security_config; - ie->radioBearerConfig->srb3_ToRelease = NULL; - ie->radioBearerConfig->drb_ToReleaseList = DRB_releaseList; - } - - /******************** Meas Config ********************/ - // measConfig - ie->measConfig = meas_config; - // lateNonCriticalExtension - ie->lateNonCriticalExtension = NULL; - // nonCriticalExtension - - if (cellGroupConfig || dedicatedNAS_MessageList) { - ie->nonCriticalExtension = calloc(1, sizeof(NR_RRCReconfiguration_v1530_IEs_t)); - if (dedicatedNAS_MessageList) - ie->nonCriticalExtension->dedicatedNAS_MessageList = dedicatedNAS_MessageList; - } - - if (cellGroupConfig != NULL) { - uint8_t *buf = NULL; - ssize_t len = uper_encode_to_new_buffer(&asn_DEF_NR_CellGroupConfig, NULL, cellGroupConfig, (void **)&buf); - AssertFatal(len > 0, "ASN1 message encoding failed (%lu)!\n", len); - if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); + // Configure Cell Group Config + if (ie->nonCriticalExtension) { + if (params->num_nas_msg) { + asn1cCalloc(ie->nonCriticalExtension->dedicatedNAS_MessageList, list); + /* dedicatedNAS-MessageList: The field is absent in case of reconfiguration with sync + otherwise it is optionally present */ + for (int i = 0; i < params->num_nas_msg; i++) { + asn1cSequenceAdd(list->list, NR_DedicatedNAS_Message_t, msg); + OCTET_STRING_fromBuf(msg, (char *)params->dedicated_NAS_msg_list[i].buf, params->dedicated_NAS_msg_list[i].len); } - ie->nonCriticalExtension->masterCellGroup = calloc(1,sizeof(OCTET_STRING_t)); - ie->nonCriticalExtension->masterCellGroup->buf = buf; - ie->nonCriticalExtension->masterCellGroup->size = len; } - dl_dcch_msg.message.choice.c1->choice.rrcReconfiguration->criticalExtensions.choice.rrcReconfiguration = ie; - - if (LOG_DEBUGFLAG(DEBUG_ASN1)) { - xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); + /* masterCellGroup */ + if (params->cell_group_config) { + // Encode in extension IE (Master cell group) + uint8_t *buf = NULL; + ssize_t len = uper_encode_to_new_buffer(&asn_DEF_NR_CellGroupConfig, NULL, params->cell_group_config, (void **)&buf); + AssertFatal(len > 0, "ASN1 message encoding failed (%lu)!\n", len); + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)params->cell_group_config); + } + ie->nonCriticalExtension->masterCellGroup = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterCellGroup)); + *ie->nonCriticalExtension->masterCellGroup = (OCTET_STRING_t){.buf = buf, .size = len}; } - enc_rval = uper_encode_to_buffer(&asn_DEF_NR_DL_DCCH_Message, - NULL, - (void *)&dl_dcch_msg, - buffer, - buffer_size); - - AssertFatal(enc_rval.encoded >0, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - - // don't free what we did not allocate, so set fields with pointers to NULL - // if memory comes from outside - ie->measConfig = NULL; - if (ie->radioBearerConfig) { - ie->radioBearerConfig->srb_ToAddModList = NULL; - ie->radioBearerConfig->drb_ToAddModList = NULL; - ie->radioBearerConfig->securityConfig = NULL; - ie->radioBearerConfig->srb3_ToRelease = NULL; - ie->radioBearerConfig->drb_ToReleaseList = NULL; + /* masterKeyUpdate */ + if (params->masterKeyUpdate) { + ie->nonCriticalExtension->masterKeyUpdate = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterKeyUpdate)); + ie->nonCriticalExtension->masterKeyUpdate->keySetChangeIndicator = false; + ie->nonCriticalExtension->masterKeyUpdate->nextHopChainingCount = params->nextHopChainingCount; } - if (ie->nonCriticalExtension) - ie->nonCriticalExtension->dedicatedNAS_MessageList = NULL; + } + + return ie; +} + +byte_array_t do_RRCReconfiguration(const nr_rrc_reconfig_param_t *params) +{ + byte_array_t msg = {.buf = NULL, .len = 0}; + NR_RRCReconfiguration_IEs_t *ie = build_RRCReconfiguration_IEs(params); + + NR_DL_DCCH_Message_t dl_dcch_msg = {0}; + dl_dcch_msg.message.present = NR_DL_DCCH_MessageType_PR_c1; + + asn1cCalloc(dl_dcch_msg.message.choice.c1, c1); + c1->present = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; + asn1cCalloc(c1->choice.rrcReconfiguration, rrcReconf); + rrcReconf->rrc_TransactionIdentifier = params->transaction_id; + rrcReconf->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; + rrcReconf->criticalExtensions.choice.rrcReconfiguration = ie; + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); + } + + int val = uper_encode_to_new_buffer(&asn_DEF_NR_DL_DCCH_Message, NULL, &dl_dcch_msg, (void **)&msg.buf); + if (val <= 0) { + LOG_E(NR_RRC, "Failed to encode DL-DCCH message\n"); ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); - LOG_D(NR_RRC, - "RRCReconfiguration for UE %d: Encoded %zd bits (%zd bytes)\n", - rrc_ue_id, - enc_rval.encoded, - (enc_rval.encoded + 7) / 8); + return msg; + } + msg.len = val; + LOG_D(NR_RRC, "RRCReconfiguration: Encoded (%ld bytes)\n", msg.len); - return((enc_rval.encoded+7)/8); + // Do not free what is not allocated in this context + ie->measConfig = NULL; + if (ie->radioBearerConfig) { + ie->radioBearerConfig->securityConfig = NULL; + ie->radioBearerConfig->drb_ToReleaseList = NULL; + ie->radioBearerConfig->srb_ToAddModList = NULL; + ie->radioBearerConfig->drb_ToAddModList = NULL; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); + + return msg; } int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv, uint64_t fiveG_S_TMSI) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index afc9226b17..83be12d87b 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -51,10 +51,24 @@ #include "NR_SRB-ToAddModList.h" #include "NR_SecurityConfig.h" #include "ds/seq_arr.h" +#include "ds/byte_array.h" #include "rrc_messages_types.h" -struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList; struct asn_TYPE_descriptor_s; +typedef struct { + uint8_t transaction_id; + NR_SRB_ToAddModList_t *srb_config_list; + NR_DRB_ToAddModList_t *drb_config_list; + NR_DRB_ToReleaseList_t *drb_release_list; + NR_SecurityConfig_t *security_config; + NR_MeasConfig_t *meas_config; + byte_array_t dedicated_NAS_msg_list[MAX_DRBS_PER_UE]; + int num_nas_msg; + NR_CellGroupConfig_t *cell_group_config; + bool masterKeyUpdate; + int nextHopChainingCount; +} nr_rrc_reconfig_param_t; + /* * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) * output into the chosen string buffer. @@ -91,17 +105,7 @@ int do_NR_SA_UECapabilityEnquiry(uint8_t *const buffer, const uint8_t Transactio int do_NR_RRCRelease(uint8_t *buffer, size_t buffer_size, uint8_t Transaction_id); -int do_RRCReconfiguration(int rrc_ue_id, - uint8_t *buffer, - size_t buffer_size, - uint8_t Transaction_id, - NR_SRB_ToAddModList_t *SRB_configList, - NR_DRB_ToAddModList_t *DRB_configList, - NR_DRB_ToReleaseList_t *DRB_releaseList, - NR_SecurityConfig_t *security_config, - NR_MeasConfig_t *meas_config, - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList, - NR_CellGroupConfig_t *cellGroupConfig); +byte_array_t do_RRCReconfiguration(const nr_rrc_reconfig_param_t *params); int do_RRCSetupComplete(uint8_t *buffer, size_t buffer_size, diff --git a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp index 347c35d3ea..1f92c5aae5 100644 --- a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp +++ b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp @@ -20,14 +20,22 @@ */ #include +#ifdef __cplusplus extern "C" { +#endif #include "openair2/RRC/NR/MESSAGES/asn1_msg.h" #include "common/ran_context.h" #include #include "common/utils/assertions.h" #include "common/utils/LOG/log.h" +#include "NR_DRB-ToAddMod.h" +#include "NR_DRB-ToAddModList.h" +#include "NR_SRB-ToAddModList.h" +#include "ds/byte_array.h" RAN_CONTEXT_t RC; +#ifdef __cplusplus } +#endif TEST(nr_asn1, rrc_reject) { @@ -77,6 +85,77 @@ TEST(nr_asn1, paging) EXPECT_GT(do_NR_Paging(0, buf, 0), 0); } +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) +{ + ASN_STRUCT_FREE(asn_DEF_NR_MeasConfig, params.meas_config); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config); + for (int i = 0; i < params.num_nas_msg; i++) + FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]); +} + +TEST(nr_asn1, rrc_reconfiguration) +{ + // SRB Configuration + NR_SRB_ToAddModList_t *srb_config_list = (NR_SRB_ToAddModList_t *)calloc_or_fail(1, sizeof(*srb_config_list)); + for (int i = 0; i < 4; i++) { + if (i == 1 || i == 2) { + NR_SRB_ToAddMod_t *srb = (NR_SRB_ToAddMod_t *)calloc_or_fail(1, sizeof(*srb)); + ASN_SEQUENCE_ADD(&srb_config_list->list, srb); + srb->srb_Identity = i; + if (i == 1 || i == 2) { + srb->reestablishPDCP = (long *)calloc_or_fail(1, sizeof(*srb->reestablishPDCP)); + *srb->reestablishPDCP = 0; + } + } + } + + // DRB Configuration + NR_DRB_ToAddModList_t *drb_config_list = (NR_DRB_ToAddModList_t *)calloc_or_fail(1, sizeof(*drb_config_list)); + for (int i = 0; i < 32; i++) { + if (i == 1 || i == 2) { + NR_DRB_ToAddMod_t *drb = (NR_DRB_ToAddMod_t *)calloc_or_fail(1, sizeof(*drb)); + ASN_SEQUENCE_ADD(&drb_config_list->list, drb); + drb->drb_Identity = i; + drb->reestablishPDCP = (long *)calloc_or_fail(1, sizeof(*drb->reestablishPDCP)); + *drb->reestablishPDCP = 0; + } + } + + // nr_rrc_reconfig_param_t setup + nr_rrc_reconfig_param_t params = {}; + params.srb_config_list = srb_config_list; + params.drb_config_list = drb_config_list; + params.num_nas_msg = 2; + params.masterKeyUpdate = false; + params.nextHopChainingCount = 1; + + byte_array_t nas_pdu_1; + nas_pdu_1.buf = (uint8_t *)malloc_or_fail(4); + memcpy(nas_pdu_1.buf, "NAS1", 4); + nas_pdu_1.len = 4; + + byte_array_t nas_pdu_2; + nas_pdu_2.buf = (uint8_t *)malloc_or_fail(4); + memcpy(nas_pdu_2.buf, "NAS2", 4); + nas_pdu_2.len = 4; + + params.dedicated_NAS_msg_list[0] = nas_pdu_1; + params.dedicated_NAS_msg_list[1] = nas_pdu_2; + + byte_array_t msg = do_RRCReconfiguration(¶ms); + + EXPECT_GT(msg.len, 0); + EXPECT_NE(msg.buf, nullptr); + + LOG_D(NR_RRC, "RRCReconfiguration: Encoded (%ld bytes)\n", msg.len); + + free_byte_array(msg); + free_RRCReconfiguration_params(params); +} + int main(int argc, char **argv) { logInit(); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 4546f59723..66f9911c8a 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -38,6 +38,7 @@ #include "NR_CG-Config.h" #include "NR_CG-ConfigInfo.h" #include "NR_RRCReconfiguration.h" +#include "RRC/NR/MESSAGES/asn1_msg.h" void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id); void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp); @@ -112,6 +113,8 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, int n_rel_drbs, const f1ap_drb_to_be_released_t *rel_drbs); +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params); + pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession); f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param); void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b924bfd0d0..e8c0edf441 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -125,12 +125,6 @@ static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_i data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd); } -static void freeDRBlist(NR_DRB_ToAddModList_t *list) -{ - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); - return; -} - static bool eq_cell_id(const void *vval, const void *vit) { const int *cell_id = (const int *)vval; @@ -551,15 +545,23 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a return rc_A3; } -static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, - gNB_RRC_UE_t *UE, - uint8_t xid, - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *nas_messages, - uint8_t *buf, - int max_len, - bool reestablish) +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) { - NR_CellGroupConfig_t *cellGroupConfig = UE->masterCellGroup; + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config); + for (int i = 0; i < params.num_nas_msg; i++) + FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]); +} + +/** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ +static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + bool srb_reestablish, + bool drb_reestablish) +{ + uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); nr_rrc_du_container_t *du = get_du_for_ue(rrc, UE->rrc_ue_id); DevAssert(du != NULL); f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; @@ -617,71 +619,71 @@ static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, UE->measConfig = measconfig; - NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, reestablish); - NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, reestablish); + // Re-establish PDCP for SRB2 only + NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reestablish); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); + nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup, + .transaction_id = xid, + .drb_config_list = DRBs, + .drb_release_list = UE->DRB_ReleaseList, + .meas_config = UE->measConfig, + .srb_config_list = SRBs}; + UE->DRB_ReleaseList = NULL; // pointer transferred to params - int size = do_RRCReconfiguration(UE->rrc_ue_id, - buf, - max_len, - xid, - SRBs, - DRBs, - UE->DRB_ReleaseList, - NULL, - measconfig, - nas_messages, - cellGroupConfig); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buf, size, "[MSG] RRC Reconfiguration\n"); - freeSRBlist(SRBs); - freeDRBlist(DRBs); - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, UE->DRB_ReleaseList); - UE->DRB_ReleaseList = NULL; + for (int i = 0; i < UE->nb_of_pdusessions; i++) { + if (UE->pduSession[i].param.nas_pdu.len > 0) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->pduSession[i].param.nas_pdu; + UE->pduSession[i].param.nas_pdu.buf = NULL; + UE->pduSession[i].param.nas_pdu.len = 0; + LOG_D(NR_RRC, "Transfer NAS info with size %ld (pdusession idx %d) to RRCReconfiguration params\n", UE->pduSession[i].param.nas_pdu.len, i); + } + } + if (UE->nas_pdu.len > 0) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->nas_pdu; + UE->nas_pdu.buf = NULL; + UE->nas_pdu.len = 0; + LOG_D(NR_RRC, "Transfer NAS info with size %ld to RRCReconfiguration params\n", UE->nas_pdu.len); + } - return size; + return params; +} + +static byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params) +{ + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return msg; + } + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); + return msg; } static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) { - uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); + /* do not re-establish PDCP for any bearer */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, false, false); + ue_p->xids[params.transaction_id] = RRC_PDUSESSION_ESTABLISH; + byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, params); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; + } for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, (char *)ue_p->pduSession[i].param.nas_pdu.buf, ue_p->pduSession[i].param.nas_pdu.len); - - LOG_D(NR_RRC, "add NAS info with size %ld (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.len, i); - ue_p->pduSession[i].xid = xid; + ue_p->pduSession[i].xid = params.transaction_id; } if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; } } - if (ue_p->nas_pdu.len) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buf, ue_p->nas_pdu.len); - } - - /* If list is empty free the list and reset the address */ - if (dedicatedNAS_MessageList->list.count == 0) { - free(dedicatedNAS_MessageList); - dedicatedNAS_MessageList = NULL; - } - - /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); - - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - // TODO refactor dedicatedNAS_MessageList - int size = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, xid, dedicatedNAS_MessageList, buffer, sizeof(buffer), false); - DevAssert(size > 0 && size <= sizeof(buffer)); - - LOG_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %d, xid %d)\n", size, xid); + LOG_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %ld, xid %d)\n", msg.len, params.transaction_id); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) @@ -690,8 +692,8 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[xid] = RRC_PDUSESSION_MODIFY; - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = - CALLOC(1, sizeof(*dedicatedNAS_MessageList)); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); + nr_rrc_reconfig_param_t params = {.drb_config_list = DRBs, .transaction_id = xid}; for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; @@ -753,42 +755,27 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t session->status = PDU_SESSION_STATUS_DONE; session->xid = xid; - if (session->param.nas_pdu.buf != NULL) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list,NR_DedicatedNAS_Message_t, dedicatedNAS_Message); - OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)session->param.nas_pdu.buf, session->param.nas_pdu.len); - LOG_I(NR_RRC, "add NAS info with size %ld (pdusession id %d)\n", session->param.nas_pdu.len, session->param.pdusession_id); + if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = ue_p->pduSession[i].param.nas_pdu; } } - /* If list is empty free the list and reset the address */ - if (dedicatedNAS_MessageList->list.count == 0) { - free(dedicatedNAS_MessageList); - dedicatedNAS_MessageList = NULL; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; } - - NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); - uint8_t buffer[NR_RRC_BUF_SIZE]; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - DRBs, - NULL, - NULL, - NULL, - dedicatedNAS_MessageList, - NULL); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - freeDRBlist(DRBs); + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); /* Free all NAS PDUs */ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); - LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d)\n", ue_p->rrc_ue_id, size); + LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } //----------------------------------------------------------------------------- @@ -808,40 +795,22 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, } } - /* If list is empty free the list and reset the address */ - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = NULL; + nr_rrc_reconfig_param_t params = {.drb_release_list = DRB_Release_configList2, .transaction_id = xid}; if (nas_length > 0) { - dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, dedicatedNAS_Message); - OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)nas_buffer, nas_length); - LOG_I(NR_RRC,"add NAS info with size %d\n", nas_length); - } else { - LOG_W(NR_RRC,"dedlicated NAS list is empty\n"); + params.dedicated_NAS_msg_list[params.num_nas_msg].buf = nas_buffer; + params.dedicated_NAS_msg_list[params.num_nas_msg++].len = nas_length; } - - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - NULL, - DRB_Release_configList2, - NULL, - NULL, - dedicatedNAS_MessageList, - NULL); - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - - /* Free all NAS PDUs */ - if (nas_length > 0) { - /* Free the NAS PDU buffer and invalidate it */ - free(nas_buffer); + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; } - - LOG_I(NR_RRC, "UE %d: Generate NR_RRCReconfiguration (bytes %d)\n", ue_p->rrc_ue_id, size); + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); + LOG_I(NR_RRC, "UE %d: Generate NR_RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo) @@ -1081,32 +1050,26 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - new_xid, - SRBs, - DRBs, - NULL, - NULL, - NULL, // MeasObj_list, - NULL, - cellGroupConfig); - freeSRBlist(SRBs); - freeDRBlist(DRBs); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - - AssertFatal(size > 0, "cannot encode RRC Reconfiguration\n"); + nr_rrc_reconfig_param_t params = {.cell_group_config = cellGroupConfig, + .drb_config_list = DRBs, + .srb_config_list = SRBs, + .transaction_id = new_xid}; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; + } + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); LOG_I(NR_RRC, - "UE %d RNTI %04x: Generate NR_RRCReconfiguration after reestablishment complete (bytes %d)\n", + "UE %d RNTI %04x: Generate NR_RRCReconfiguration after reestablishment complete (bytes %ld)\n", ue_p->rrc_ue_id, ue_p->rnti, - size); + msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } -//----------------------------------------------------------------------------- int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int dl_bwp_id, const int ul_bwp_id) { @@ -1123,22 +1086,16 @@ int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int *masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = ul_bwp_id; } - uint8_t buffer[NR_RRC_BUF_SIZE]; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - masterCellGroup); - + nr_rrc_reconfig_param_t params = {.cell_group_config = masterCellGroup, .transaction_id = xid}; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return -1; + } const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); - + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_byte_array(msg); + free_RRCReconfiguration_params(params); return 0; } @@ -2192,14 +2149,23 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); UE->xids[xid] = RRC_DEDICATED_RECONF; - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = rrc_gNB_encode_RRCReconfiguration(rrc, UE, xid, NULL, buffer, sizeof(buffer), true); - DevAssert(size > 0 && size <= sizeof(buffer)); + /* 3GPP TS 38.331 specifies that PDCP shall be re-established whenever the security key + * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming + * an RRC connection, or at the first reconfiguration after RRC connection reestablishment + * in NR, do not re-establish PDCP */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, true, true); + params.transaction_id = xid; + + byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return; + } // TODO N2 38.413 sec 9.3.1.21: admitted PDU sessions (in UE), Target to // Source Transparent Container (9.3.1.21) which encodes the RRC // reconfiguration above - UE->ho_context->target->ho_req_ack(rrc, UE, buffer, size); + UE->ho_context->target->ho_req_ack(rrc, UE, msg.buf, msg.len); } } From d18830f359cb8bdfd96ad47db5a75b09fd845d52 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 1 Apr 2025 09:32:35 +0200 Subject: [PATCH 17/26] Enable PDCP re-establishment for SRB1/SRB2 based on bitmap in createSRBlist This is necessary because the function was re-establishing PDCP only for SRB2 however according to specs 3GPP TS 38.331 RadioBearerConfig, PDCP shall be re-established for SRB1 and/or SRB2 whenever the security key used for the radio bearer changes, with some exceptions for SRB1 (i.e. when resuming an RRC connection, or at the first reconfiguration after RRC connection reestablishment in NR, do not re-establish PDCP for SRB1). * the input param "reestablish" is converted into a bitmap to indicate whether PDCP should be re-established for the SRB1 and/or SRB2. * For convenience the bitmap is 0-based, with index 1 corresponding to SRB1, index 2 to SRB2. This commit is keeping the legacy re-establishment, that is re-establishment of PCDP for SRB2 only. --- openair2/RRC/NR/nr_rrc_proto.h | 3 +++ openair2/RRC/NR/rrc_gNB.c | 36 ++++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 66f9911c8a..fed265b0d6 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -40,6 +40,9 @@ #include "NR_RRCReconfiguration.h" #include "RRC/NR/MESSAGES/asn1_msg.h" +#define SRB1 1 +#define SRB2 2 + void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id); void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp); void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e8c0edf441..9a2039ebef 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -270,12 +270,17 @@ unsigned int rrc_gNB_get_next_transaction_identifier(module_id_t gnb_mod_idP) return tmp; } -/** - * @brief Create srb-ToAddModList for RRCSetup and RRCReconfiguration messages -*/ -static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, bool reestablish) +/** @brief Create srb-ToAddModList for RRCSetup and RRCReconfiguration messages + * @param reestablish bitmap to indicates whether PDCP should be re-established + * for the SRB1 and/or SRB2. For convenience the bitmap is 0-based, with index 1 + * corresponding to SRB1, index 2 to SRB2. 3GPP TS 38.331 RadioBearerConfig + * specifies that PDCP shall be re-established whenever the security key used + * for the radio bearer changes, with some expections for SRB1 (i.e. when resuming + * an RRC connection, or at the first reconfiguration after RRC connection + * reestablishment in NR, do not re-establish PDCP) */ +static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish) { - if (!ue->Srb[1].Active) { + if (!ue->Srb[SRB1].Active) { LOG_E(NR_RRC, "Call SRB list while SRB1 doesn't exist\n"); return NULL; } @@ -284,9 +289,11 @@ static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, bool reestablish) if (ue->Srb[i].Active) { asn1cSequenceAdd(list->list, NR_SRB_ToAddMod_t, srb); srb->srb_Identity = i; - /* Set reestablishPDCP only for SRB2 */ - if (reestablish && i == 2) { + /* Based on the bitmap, set reestablishPDCP for SRB1 and SRB2 */ + if ((i == SRB1 || i == SRB2) && (reestablish & (1 << i))) { asn1cCallocOne(srb->reestablishPDCP, NR_SRB_ToAddMod__reestablishPDCP_true); + } else { + DevAssert(!(reestablish & (1 << i))); } } return list; @@ -558,7 +565,7 @@ void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) /** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, - bool srb_reestablish, + uint8_t srb_reest_bitmap, bool drb_reestablish) { uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); @@ -620,8 +627,9 @@ static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, UE->measConfig = measconfig; // Re-establish PDCP for SRB2 only - NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reestablish); + NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reest_bitmap); NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); + nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup, .transaction_id = xid, .drb_config_list = DRBs, @@ -662,7 +670,7 @@ static byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) { /* do not re-establish PDCP for any bearer */ - nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, false, false); + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false); ue_p->xids[params.transaction_id] = RRC_PDUSESSION_ESTABLISH; byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, params); if (msg.len <= 0) { @@ -1043,8 +1051,10 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR /* PDCP Reestablishment of DRBs according to 5.3.5.6.5 of 3GPP TS 38.331 (over E1) */ cuup_notify_reestablishment(rrc, ue_p); - /* Create srb-ToAddModList */ - NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, true); + /* Create srb-ToAddModList, 3GPP TS 38.331 RadioBearerConfig: + * do not re-establish PDCP for SRB1, when resuming an RRC connection, + * or at the first reconfiguration after RRC connection reestablishment in NR */ + NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, 1 << SRB2); // Re-establish PDCP for SRB2 only /* Create drb-ToAddModList */ NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true); @@ -2153,7 +2163,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming * an RRC connection, or at the first reconfiguration after RRC connection reestablishment * in NR, do not re-establish PDCP */ - nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, true, true); + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, (1 << SRB2), true); params.transaction_id = xid; byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); From 60535aae9922790008e60a683166078185e2a8fd Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 19 May 2025 14:36:10 +0200 Subject: [PATCH 18/26] Use get_RRCReconfiguration_params in rrc_gNB_generate_dedicatedRRCReconfiguration --- openair2/RRC/NR/rrc_gNB.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 9a2039ebef..8851901c83 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -697,23 +697,20 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) { int qos_flow_index = 0; - uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - ue_p->xids[xid] = RRC_PDUSESSION_MODIFY; - - NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); - nr_rrc_reconfig_param_t params = {.drb_config_list = DRBs, .transaction_id = xid}; + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false); + ue_p->xids[params.transaction_id] = RRC_PDUSESSION_MODIFY; for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; // bypass the new and already configured pdu sessions if (session->status >= PDU_SESSION_STATUS_DONE) { - session->xid = xid; + session->xid = params.transaction_id; continue; } if (session->cause.type != NGAP_CAUSE_NOTHING) { // set xid of failure pdu session - session->xid = xid; + session->xid = params.transaction_id; session->status = PDU_SESSION_STATUS_FAILED; continue; } @@ -728,7 +725,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t if (j == MAX_DRBS_PER_UE) { ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_unspecified}; - session->xid = xid; + session->xid = params.transaction_id; session->status = PDU_SESSION_STATUS_FAILED; session->cause = cause; continue; @@ -753,7 +750,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t LOG_E(NR_RRC, "not supported 5qi %lu\n", session->param.qos[qos_flow_index].fiveQI); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_not_supported_5QI_value}; session->status = PDU_SESSION_STATUS_FAILED; - session->xid = xid; + session->xid = params.transaction_id; session->cause = cause; continue; } @@ -761,11 +758,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t } session->status = PDU_SESSION_STATUS_DONE; - session->xid = xid; - - if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { - params.dedicated_NAS_msg_list[params.num_nas_msg++] = ue_p->pduSession[i].param.nas_pdu; - } + session->xid = params.transaction_id; } byte_array_t msg = do_RRCReconfiguration(¶ms); @@ -774,11 +767,6 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t return; } LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); - - /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); - LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); From 7fba453329677f087546b975b0ad8a328dde23c3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 11 Apr 2025 15:59:53 +0200 Subject: [PATCH 19/26] Pass byte_array_t to handover acknowledge function The byte_array reference contains the pointer to the encoded RRC buffer to be used in the handover acknowledge callback (e.g. in F1 to trigger RRCReconfiguration) --- openair2/RRC/NR/rrc_gNB.c | 2 +- openair2/RRC/NR/rrc_gNB_mobility.c | 4 ++-- openair2/RRC/NR/rrc_gNB_mobility.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 8851901c83..a943b0d723 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2163,7 +2163,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance // TODO N2 38.413 sec 9.3.1.21: admitted PDU sessions (in UE), Target to // Source Transparent Container (9.3.1.21) which encodes the RRC // reconfiguration above - UE->ho_context->target->ho_req_ack(rrc, UE, msg.buf, msg.len); + UE->ho_context->target->ho_req_ack(rrc, UE, msg); } } diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 54c0f6f17d..df52a1bf6d 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -258,7 +258,7 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_ #endif } -static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t *rrc_reconf_buf, uint32_t rrc_reconf_len) +static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, byte_array_t buffer) { // N2/Xn HO: fill with UE caps, as-context, rrc reconf, send to source CU // also, fill the UE->rnti from the new one (in F1 case, happens after @@ -266,7 +266,7 @@ static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_ // F1 HO: handling of "source CU" information DevAssert(UE->ho_context->source != NULL); - rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, rrc_reconf_buf, rrc_reconf_len); + rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, buffer.buf, buffer.len); LOG_A(NR_RRC, "HO acknowledged: Send reconfiguration for UE %u/RNTI %04x...\n", UE->rrc_ue_id, UE->rnti); /* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331 diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index 5046176c1d..e49c8fb344 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -22,6 +22,7 @@ #define RRC_GNB_MOBILITY_H_ #include +#include "common/utils/ds/byte_array.h" /* forward declarations */ typedef struct gNB_RRC_INST_s gNB_RRC_INST; @@ -49,7 +50,7 @@ typedef struct nr_ho_source_cu { } nr_ho_source_cu_t; /* acknowledgement of handover request. buf+len is the RRC Reconfiguration */ -typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *buf, uint32_t len); +typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, byte_array_t msg); typedef void (*ho_success_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); typedef struct nr_ho_target_cu { /// pointer to the (target) DU structure From dca7e6c95d212732f0abb4bed508cdaaee8a6888 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 6 May 2025 17:22:07 +0200 Subject: [PATCH 20/26] Rework handover ack callback Inside of passing the RRCReconfiguration buffer, call RRCReconfiguration message generation inside the F1 callback. This will simplify the code in the rrc_CU_process_ue_context_setup_response() function once the N2 handover case is introduced. In rrc_CU_process_ue_context_setup_response(), with presence of the HO context, the HO ACK callback is called only once and depending on the type of HO it will do either RRCReconfiguration for F1 and HandoverCommand for N2. --- openair2/RRC/NR/nr_rrc_proto.h | 4 ++++ openair2/RRC/NR/rrc_gNB.c | 28 +++------------------------- openair2/RRC/NR/rrc_gNB_mobility.c | 17 +++++++++++++---- openair2/RRC/NR/rrc_gNB_mobility.h | 2 +- 4 files changed, 21 insertions(+), 30 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index fed265b0d6..3a4fed6411 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -118,6 +118,10 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params); +byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params); + +nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish); + pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession); f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param); void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a943b0d723..2fd479da91 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -563,10 +563,7 @@ void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) } /** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ -static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, - gNB_RRC_UE_t *UE, - uint8_t srb_reest_bitmap, - bool drb_reestablish) +nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish) { uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); nr_rrc_du_container_t *du = get_du_for_ue(rrc, UE->rrc_ue_id); @@ -656,7 +653,7 @@ static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, return params; } -static byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params) +byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params) { byte_array_t msg = do_RRCReconfiguration(¶ms); if (msg.len <= 0) { @@ -2144,26 +2141,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance DevAssert(resp->crnti != NULL); UE->ho_context->target->du_ue_id = resp->gNB_DU_ue_id; UE->ho_context->target->new_rnti = *resp->crnti; - - uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - UE->xids[xid] = RRC_DEDICATED_RECONF; - /* 3GPP TS 38.331 specifies that PDCP shall be re-established whenever the security key - * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming - * an RRC connection, or at the first reconfiguration after RRC connection reestablishment - * in NR, do not re-establish PDCP */ - nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, (1 << SRB2), true); - params.transaction_id = xid; - - byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); - if (msg.len <= 0) { - LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); - return; - } - - // TODO N2 38.413 sec 9.3.1.21: admitted PDU sessions (in UE), Target to - // Source Transparent Container (9.3.1.21) which encodes the RRC - // reconfiguration above - UE->ho_context->target->ho_req_ack(rrc, UE, msg); + UE->ho_context->target->ho_req_ack(rrc, UE); } } diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index df52a1bf6d..647f253989 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -258,11 +258,20 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_ #endif } -static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, byte_array_t buffer) +static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) { - // N2/Xn HO: fill with UE caps, as-context, rrc reconf, send to source CU - // also, fill the UE->rnti from the new one (in F1 case, happens after - // confirmation of ue ctxt modif + /* 3GPP TS 38.331 specifies that PDCP shall be re-established whenever the security key + * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming + * an RRC connection, or at the first reconfiguration after RRC connection reestablishment + * in NR, do not re-establish PDCP */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, (1 << SRB2), true); + UE->xids[params.transaction_id] = RRC_DEDICATED_RECONF; + byte_array_t buffer = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); + free_RRCReconfiguration_params(params); + if (!buffer.len) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return; + } // F1 HO: handling of "source CU" information DevAssert(UE->ho_context->source != NULL); diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index e49c8fb344..6e9bcbcfe6 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -50,7 +50,7 @@ typedef struct nr_ho_source_cu { } nr_ho_source_cu_t; /* acknowledgement of handover request. buf+len is the RRC Reconfiguration */ -typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, byte_array_t msg); +typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); typedef void (*ho_success_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); typedef struct nr_ho_target_cu { /// pointer to the (target) DU structure From 70239c086c0f1269673e1ebde430ce29ad881534 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 16:41:46 +0200 Subject: [PATCH 21/26] Fix memory leak in fill_measurement_configuration seq_arr_push_back is doing a memcpy so locally allocated memory can be freed after. Allocate in stack. > Direct leak of 64 byte(s) in 2 object(s) allocated from: > #0 0x7ec4bb8b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 > #1 0x55895aae1b1f in fill_measurement_configuration /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:2015 > #2 0x55895aae1b1f in RCconfig_NRRRC /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:2112 > #3 0x55895a246112 in create_gNB_tasks /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:253 > #4 0x55895a246112 in main /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:619 > #5 0x7ec4ba229d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 --- openair2/GNB_APP/gnb_config.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 70e6c026ca..152e87bd20 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2020,22 +2020,21 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) measurementConfig->a3_event_list = malloc(sizeof(seq_arr_t)); seq_arr_init(measurementConfig->a3_event_list, sizeof(nr_a3_event_t)); for (int i = 0; i < A3_EventList.numelt; i++) { - nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t)); - AssertFatal(a3_event != NULL, "out of memory\n"); - a3_event->pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; - AssertFatal(a3_event->pci >= -1 && a3_event->pci < 1024, + nr_a3_event_t a3_event = {0}; + a3_event.pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; + AssertFatal(a3_event.pci >= -1 && a3_event.pci < 1024, "entry %s.%s must be -1<=PCI<1024, but is %d\n", measurement_path, MEASUREMENT_EVENTS_PCI_ID, - a3_event->pci); - a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; - a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; - a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; + a3_event.pci); + a3_event.timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; + a3_event.a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; + a3_event.hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; - if (a3_event->pci == -1) + if (a3_event.pci == -1) measurementConfig->is_default_a3_configuration_exists = true; - seq_arr_push_back(measurementConfig->a3_event_list, a3_event, sizeof(nr_a3_event_t)); + seq_arr_push_back(measurementConfig->a3_event_list, &a3_event, sizeof(nr_a3_event_t)); } } From abcc00945e3433b67a5c81235e8ee2d683cbcc2d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 17:27:51 +0200 Subject: [PATCH 22/26] Fix memory leak in fill_neighbour_cell_configuration the dynamically allocated memory is pushed to the seq_arr that is doing a memcpy, so it can be either or better allocated in the stack instead > Direct leak of 48 byte(s) in 1 object(s) allocated from: > #0 0x7d4c934b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 > #1 0x577622a40137 in fill_neighbour_cell_configuration /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:1933 > #2 0x577622a40137 in RCconfig_NRRRC /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:2109 > #3 0x5776221a30f2 in create_gNB_tasks /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:253 > #4 0x5776221a30f2 in main /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:619 > #5 0x7d4c91e29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 --- openair2/GNB_APP/gnb_config.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 152e87bd20..8123f65dff 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1938,14 +1938,13 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc AssertFatal(cell->neighbour_cells != NULL, "Memory exhausted!!!"); seq_arr_init(cell->neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); for (int l = 0; l < NeighbourCellParamList.numelt; ++l) { - nr_neighbour_gnb_configuration_t *neighbourCell = calloc(1, sizeof(nr_neighbour_gnb_configuration_t)); - AssertFatal(neighbourCell != NULL, "out of memory\n"); - neighbourCell->gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); - neighbourCell->nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); - neighbourCell->physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; - neighbourCell->subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr; - neighbourCell->absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr; - neighbourCell->tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; + nr_neighbour_gnb_configuration_t neighbourCell = {0}; + neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); + neighbourCell.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); + neighbourCell.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; + neighbourCell.subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr; + neighbourCell.absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr; + neighbourCell.tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; char neighbour_plmn_path[CONFIG_MAXOPTLENGTH]; snprintf(neighbour_plmn_path, @@ -1957,10 +1956,10 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNB_CONFIG_STRING_NEIGHBOUR_PLMN); GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path); - neighbourCell->plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - neighbourCell->plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; - neighbourCell->plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; - seq_arr_push_back(cell->neighbour_cells, neighbourCell, sizeof(nr_neighbour_gnb_configuration_t)); + neighbourCell.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + neighbourCell.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; + neighbourCell.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; + seq_arr_push_back(cell->neighbour_cells, &neighbourCell, sizeof(nr_neighbour_gnb_configuration_t)); } seq_arr_push_back(rrc->neighbour_cell_configuration, cell, sizeof(neighbour_cell_configuration_t)); From 12d9e1f11675ef76bce45fc40cd2a70bd7fa841a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 17:49:47 +0200 Subject: [PATCH 23/26] Fix memory leak in fill_neighbour_cell_configuration dynamically allocated memory is pushed to the seq_arr that is doing a memcpy, so it can be either or better allocated in the stack instead > Direct leak of 16 byte(s) in 1 object(s) allocated from: > #0 0x7efd8f6b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 > #1 0x577888f3457e in fill_neighbour_cell_configuration /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:1914 > #2 0x577888f3457e in RCconfig_NRRRC /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:2108 > #3 0x57788869a0d2 in create_gNB_tasks /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:253 > #4 0x57788869a0d2 in main /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:619 > #5 0x7efd8e029d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 --- openair2/GNB_APP/gnb_config.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 8123f65dff..d243421d2a 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1919,9 +1919,8 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc seq_arr_init(rrc->neighbour_cell_configuration, sizeof(neighbour_cell_configuration_t)); for (int elm = 0; elm < neighbour_list_param_list.numelt; ++elm) { - neighbour_cell_configuration_t *cell = calloc(1, sizeof(neighbour_cell_configuration_t)); - AssertFatal(cell != NULL, "out of memory\n"); - cell->nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr; + neighbour_cell_configuration_t cell = {0}; + cell.nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr; char neighbourpath[MAX_OPTNAME_SIZE + 8]; snprintf(neighbourpath, sizeof(neighbourpath), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm); @@ -1930,13 +1929,12 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNBNEIGHBOURCELLPARAMS_DESC, GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, neighbourpath); - LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt); + LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell.nr_cell_id, NeighbourCellParamList.numelt); if (NeighbourCellParamList.numelt < 1) continue; - cell->neighbour_cells = malloc(sizeof(seq_arr_t)); - AssertFatal(cell->neighbour_cells != NULL, "Memory exhausted!!!"); - seq_arr_init(cell->neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); + cell.neighbour_cells = malloc_or_fail(sizeof(seq_arr_t)); + seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); for (int l = 0; l < NeighbourCellParamList.numelt; ++l) { nr_neighbour_gnb_configuration_t neighbourCell = {0}; neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); @@ -1959,10 +1957,9 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc neighbourCell.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; neighbourCell.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; neighbourCell.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; - seq_arr_push_back(cell->neighbour_cells, &neighbourCell, sizeof(nr_neighbour_gnb_configuration_t)); + seq_arr_push_back(cell.neighbour_cells, &neighbourCell, sizeof(neighbourCell)); } - - seq_arr_push_back(rrc->neighbour_cell_configuration, cell, sizeof(neighbour_cell_configuration_t)); + seq_arr_push_back(rrc->neighbour_cell_configuration, &cell, sizeof(cell)); } void *base = seq_arr_front(rrc->neighbour_cell_configuration); size_t nmemb = seq_arr_size(rrc->neighbour_cell_configuration); From 114f833a7740103004756821c18c938ff905370a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 17:58:19 +0200 Subject: [PATCH 24/26] Fix memory leak in createSRBlist ASN_SEQUENCE_ADD is calling realloc which is allocating memory for the 'array' which was not freed. > Direct leak of 32 byte(s) in 1 object(s) allocated from: > #0 0x7ce97deb4c38 in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:164 > #1 0x5813fba02574 in asn_set_add /openairinterface5g/n2-handover-preparation/cmake_targets/ran_build/build/openair2/RRC/LTE/MESSAGES/asn_SET_OF.c:27 > #2 0x5813faf6c672 in createSRBlist /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:331 > #3 0x5813faf9aa78 in rrc_gNB_generate_RRCSetup /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:421 > #4 0x5813fafba2ee in rrc_handle_RRCSetupRequest /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:1243 > #5 0x5813fafba2ee in rrc_gNB_process_initial_ul_rrc_message /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2019 > #6 0x5813fafcdc3a in rrc_gnb_task /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2761 > #7 0x7ce97c894ac2 in start_thread nptl/pthread_create.c:442 > Direct leak of 32 byte(s) in 1 object(s) allocated from: > #0 0x7ce97deb4c38 in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:164 > #1 0x5813fba02574 in asn_set_add /openairinterface5g/n2-handover-preparation/cmake_targets/ran_build/build/openair2/RRC/LTE/MESSAGES/asn_SET_OF.c:27 > #2 0x5813faf6c672 in createSRBlist /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:331 > #3 0x5813faf7d89d in get_RRCReconfiguration_params /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:660 > #4 0x5813faf914b3 in rrc_gNB_generate_dedicatedRRCReconfiguration /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:716 > #5 0x5813faf96856 in rrc_CU_process_ue_context_setup_response /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2190 > #6 0x5813fafcd3ed in rrc_gnb_task /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2796 > #7 0x7ce97c894ac2 in start_thread nptl/pthread_create.c:442 --- openair2/RRC/NR/rrc_gNB.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2fd479da91..ba324f4bad 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -322,12 +322,7 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) static void freeSRBlist(NR_SRB_ToAddModList_t *l) { - if (l) { - for (int i = 0; i < l->list.count; i++) - free(l->list.array[i]); - free(l); - } else - LOG_E(NR_RRC, "Call free SRB list on NULL pointer\n"); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, l); } static void activate_srb(gNB_RRC_UE_t *UE, int srb_id) From a06457bab62db2705d7e88c9113aad99ecbb48d9 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 5 Jun 2025 11:25:38 +0200 Subject: [PATCH 25/26] Fix direct leak in rrc_gNB_send_NGAP_NAS_FIRST_REQ Free memory allocated in NGAP after use in RRC. Direct leak of 29 byte(s) in 1 object(s) allocated from: > #0 0x7f11200b4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145 > #1 0x558b7fcd0137 in malloc_or_fail /n2-handover-preparation/common/utils/utils.h:86 > #2 0x558b7fcd0137 in create_byte_array /n2-handover-preparation/common/utils/ds/byte_array.c:32 > #3 0x558b7fdb7a5c in rrc_gNB_send_NGAP_NAS_FIRST_REQ /n2-handover-preparation/openair2/RRC/NR/rrc_gNB_NGAP.c:183 > #4 0x558b7fd2ab30 in rrc_gNB_process_RRCSetupComplete /n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:439 > #5 0x558b7fd2ab30 in handle_rrcSetupComplete /n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:1715 > #6 0x558b7fd63e23 in rrc_gNB_decode_dcch /n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:1851 > #7 0x558b7fd8b4c3 in rrc_gnb_task /n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2718 > #8 0x7f111ea94ac2 in start_thread nptl/pthread_create.c:442 --- openair3/NGAP/ngap_gNB.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index 488345261d..ae8d806e18 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -313,6 +313,7 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { case NGAP_NAS_FIRST_REQ: ngap_gNB_handle_nas_first_req(instance, &NGAP_NAS_FIRST_REQ(received_msg)); + free_byte_array(NGAP_NAS_FIRST_REQ(received_msg).nas_pdu); break; case NGAP_UPLINK_NAS: From 03b6e32fdbfcc94d38070eaced42101d45f04278 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 10 Jun 2025 10:47:11 +0200 Subject: [PATCH 26/26] Rename nr_neighbour_gnb_configuration_t to nr_neighbour_cell_t for clarity --- openair2/GNB_APP/gnb_config.c | 4 ++-- openair2/RRC/NR/nr_rrc_defs.h | 2 +- openair2/RRC/NR/rrc_gNB.c | 10 +++++----- openair2/RRC/NR/rrc_gNB_du.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index d243421d2a..a2112d46eb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1934,9 +1934,9 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc continue; cell.neighbour_cells = malloc_or_fail(sizeof(seq_arr_t)); - seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); + seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_cell_t)); for (int l = 0; l < NeighbourCellParamList.numelt; ++l) { - nr_neighbour_gnb_configuration_t neighbourCell = {0}; + nr_neighbour_cell_t neighbourCell = {0}; neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); neighbourCell.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); neighbourCell.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 7e0789c4ad..640803af2f 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -301,7 +301,7 @@ typedef struct { plmn_identity_t plmn; uint32_t tac; bool isIntraFrequencyNeighbour; -} nr_neighbour_gnb_configuration_t; +} nr_neighbour_cell_t; typedef struct neighbour_cell_configuration_s { uint64_t nr_cell_id; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index ba324f4bad..f69e03b810 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -150,18 +150,18 @@ const neighbour_cell_configuration_t *get_neighbour_cell_config(const gNB_RRC_IN static bool eq_pci(const void *vval, const void *vit) { const int *pci = (const int *)vval; - const nr_neighbour_gnb_configuration_t *neighbour = (const nr_neighbour_gnb_configuration_t *)vit; + const nr_neighbour_cell_t *neighbour = (const nr_neighbour_cell_t *)vit; return neighbour->physicalCellId == *pci; } -const nr_neighbour_gnb_configuration_t *get_neighbour_gnb_by_pci(const neighbour_cell_configuration_t *cell, int pci) +const nr_neighbour_cell_t *get_neighbour_cell_by_pci(const neighbour_cell_configuration_t *cell, int pci) { seq_arr_t *head = cell->neighbour_cells; DevAssert(head != NULL); LOG_D(NR_RRC, "Number of neighbour cells: %ld\n", head->size); elm_arr_t e = find_if(head, &pci, eq_pci); if (e.found) { - const nr_neighbour_gnb_configuration_t *neighbour = (const nr_neighbour_gnb_configuration_t *)e.it; + const nr_neighbour_cell_t *neighbour = (const nr_neighbour_cell_t *)e.it; LOG_D(NR_RRC, "Found matching neighbour cell with PCI %d and Cell ID %ld\n", neighbour->physicalCellId, neighbour->nrcell_id); return neighbour; } @@ -593,7 +593,7 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC LOG_D(NR_RRC, "HO LOG: Preparing A3 Event Measurement Configuration!\n"); bool is_default_a3_added = false; for (int i = 0; i < neighbour_cells->size; i++) { - nr_neighbour_gnb_configuration_t *neighbourCell = (nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbour_cells, i); + nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i); if (!neighbourCell->isIntraFrequencyNeighbour) continue; seq_arr_push_back(pci_seq, &neighbourCell->physicalCellId, sizeof(int)); @@ -1401,7 +1401,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbour_pci); const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(scell_pci); const neighbour_cell_configuration_t *cell = get_neighbour_cell_config(rrc, serving_cell->nr_cellid); - const nr_neighbour_gnb_configuration_t *neighbour = get_neighbour_gnb_by_pci(cell, neighbour_pci); + const nr_neighbour_cell_t *neighbour = get_neighbour_cell_by_pci(cell, neighbour_pci); // CU does not have f1 connection with neighbour cell context. So check does serving cell has this phyCellId as a // neighbour. if (!neigh_cell && neighbour) { diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 9e89766acb..a650a03604 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -202,7 +202,7 @@ const struct f1ap_served_cell_info_t *get_cell_information_by_phycellId(int phyC static void is_intra_frequency_neighbour(void *ssb_arfcn, void *neighbour_cell) { uint32_t *ssb_arfcn_ptr = (uint32_t *)ssb_arfcn; - nr_neighbour_gnb_configuration_t *neighbour_cell_ptr = (nr_neighbour_gnb_configuration_t *)neighbour_cell; + nr_neighbour_cell_t *neighbour_cell_ptr = (nr_neighbour_cell_t *)neighbour_cell; if (*ssb_arfcn_ptr == neighbour_cell_ptr->absoluteFrequencySSB) { LOG_D(NR_RRC, "HO LOG: found intra frequency neighbour %lu!\n", neighbour_cell_ptr->nrcell_id); @@ -237,7 +237,7 @@ static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_config for (int c = 0; c < neighbour_cell_configuration->size; c++) { const neighbour_cell_configuration_t *neighbour_config = seq_arr_at(neighbour_cell_configuration, c); for (int ni = 0; ni < neighbour_config->neighbour_cells->size; ni++) { - const nr_neighbour_gnb_configuration_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); + const nr_neighbour_cell_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); if (nc->nrcell_id != cell->nr_cellid) continue; // current cell is in the nc config, check that config matches