From 419a14a8138210b325ba6f771210ffb2ebc2951e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 24 Jul 2024 14:32:23 +0200 Subject: [PATCH 01/33] Demote log message of ITTI thread creation --- common/utils/ocp_itti/intertask_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp index 9d22e06d7d..b59de2e0fc 100644 --- a/common/utils/ocp_itti/intertask_interface.cpp +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -320,7 +320,7 @@ typedef struct timer_elm_s { (char *)itti_get_task_name(task_id), -1, OAI_PRIORITY_RT); - LOG_I(ITTI,"Created Posix thread %s\n", itti_get_task_name(task_id) ); + LOG_D(ITTI,"Created Posix thread %s\n", itti_get_task_name(task_id) ); return 0; } From 798a62271c6d97508fef4fc084144876c638d1fe Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Aug 2024 14:44:53 +0200 Subject: [PATCH 02/33] DL RRC message: print log if oldUE unknown --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 2435ed629a..426a72f391 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -743,7 +743,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) * the new UE context (with new C-RNTI), but set up everything to reuse the * old config. */ NR_UE_info_t *oldUE = find_nr_UE(&mac->UE_info, *dl_rrc->old_gNB_DU_ue_id); - DevAssert(oldUE); + AssertFatal(oldUE, "CU claims we should know UE %04x, but we don't\n", *dl_rrc->old_gNB_DU_ue_id); pthread_mutex_lock(&mac->sched_lock); /* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it * from the current configuration. Also, expect the reconfiguration from From 9b7d3351a14b15d6b5e451cad16826a646b58fdc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Aug 2024 16:41:39 +0200 Subject: [PATCH 03/33] DU: if requested to remove non-existing UE, just ack The failure mode observed here was that the CU sent a release command for a UE that the DU does not know. Given, that the outcome of the release command (no UE) is equal to the current state (no UE), from the DU point of view, we can safely ack the command. --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 426a72f391..9b5bd938ec 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -669,8 +669,12 @@ void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd) NR_SCHED_LOCK(&mac->sched_lock); NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, cmd->gNB_DU_ue_id); if (UE == NULL) { - LOG_E(MAC, "ERROR: unknown UE with RNTI %04x, ignoring UE Context Release Command\n", cmd->gNB_DU_ue_id); NR_SCHED_UNLOCK(&mac->sched_lock); + f1ap_ue_context_release_complete_t complete = { + .gNB_CU_ue_id = cmd->gNB_CU_ue_id, + .gNB_DU_ue_id = cmd->gNB_DU_ue_id, + }; + mac->mac_rrc.ue_context_release_complete(&complete); return; } From ec6469d0888414bda9b10e54a4963aa0579cb04a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 8 Aug 2024 08:31:21 +0200 Subject: [PATCH 04/33] F1AP: Remove unnecessary logs --- openair2/F1AP/f1ap_du_ue_context_management.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 8c32e7bea6..5ab1c07d6c 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -281,12 +281,9 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i memcpy(f1ap_ue_context_setup_req->rrc_container, ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); f1ap_ue_context_setup_req->rrc_container_length = ieRRC->value.choice.RRCContainer.size; - // AssertFatal(0, "check configuration, send to appropriate handler\n"); } else { LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n"); } - } else { - LOG_W(F1AP, "can't find RRCContainer in UEContextSetupRequestIEs by id %ld \n", F1AP_ProtocolIE_ID_id_RRCContainer); } ue_context_setup_request(f1ap_ue_context_setup_req); From 25430e9b25c9ce4e31f50f728bf6ac9034dce99b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 4 Sep 2024 18:11:15 +0200 Subject: [PATCH 05/33] Fixup: on SCTP conn event, transmit assoc_id User of the SCTP module use the assoc_id for connection identification. The previous code set the assoc_id to -1, so there is no way of telling which connection broke. Use the assoc_id instead --- openair3/SCTP/sctp_eNB_task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index ffd4bba3f5..a6d3a11a39 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -787,7 +787,7 @@ sctp_eNB_read_from_socket( SCTP_ERROR("sctp_recvmsg (fd %d, len %d ): %s:%d\n", sctp_cnx->sd, n, strerror(errno), errno); sctp_itti_send_association_resp( - sctp_cnx->task_id, sctp_cnx->instance, -1, + sctp_cnx->task_id, sctp_cnx->instance, sctp_cnx->assoc_id, sctp_cnx->cnx_id, SCTP_STATE_UNREACHABLE, 0, 0); close(sctp_cnx->sd); From ba0b63fe2fe9dcffadcdb1bdd73eb97872889b8b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Aug 2024 15:02:30 +0200 Subject: [PATCH 06/33] F1AP: Handle SCTP communication lost It can happen that SCTP communication is simply lost, e.g. [SCTP] SCTP_ASSOC_CHANGE to SCTP_COMM_LOST [SCTP] sctp_recvmsg (fd 104, len -1 ): Connection reset by peer:104 The previous code only handled the SHUTDOWN event, but in abnormal situations, we should also handle the connection state change and signal to RRC that the endpoint is dead, which is now implemented. --- openair2/F1AP/f1ap_cu_task.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c index a320b92935..72e3d86ea2 100644 --- a/openair2/F1AP/f1ap_cu_task.c +++ b/openair2/F1AP/f1ap_cu_task.c @@ -64,27 +64,17 @@ static void cu_task_handle_sctp_association_ind(instance_t instance, static void cu_task_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) { DevAssert(sctp_new_association_resp != NULL); - if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) { + enum sctp_state_e state = sctp_new_association_resp->sctp_state; + if (state != SCTP_STATE_ESTABLISHED) { f1ap_cudu_inst_t *f1ap_cu_data = getCxt(instance); AssertFatal(f1ap_cu_data != NULL, "illegal state: SCTP shutdown for non-existing F1AP endpoint\n"); - LOG_I(F1AP, "Received SCTP shutdown for assoc_id %d, removing endpoint\n", sctp_new_association_resp->assoc_id); + LOG_I(F1AP, "Received SCTP state %d for assoc_id %d, removing endpoint\n", state, sctp_new_association_resp->assoc_id); /* inform RRC that the DU is gone */ MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_LOST_CONNECTION); message_p->ittiMsgHeader.originInstance = sctp_new_association_resp->assoc_id; itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p); return; } - - if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { - LOG_W(F1AP, "Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n", - sctp_new_association_resp->sctp_state, - instance, - sctp_new_association_resp->ulp_cnx_id); - //if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) - //proto_agent_stop(instance); - //f1ap_handle_setup_message(instance, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN); - return; // exit -1 for debugging - } } static void cu_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) { From 32b2ad259d321780c213cbec46f6bba010971aa7 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Aug 2024 13:37:05 +0200 Subject: [PATCH 07/33] Harmonize Msg3 PUSCH LOG_A to be only one, demote RA cont res timer --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index d8f6690818..160cde63f5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -560,7 +560,7 @@ static void start_ra_contention_resolution_timer(NR_RA_t *ra, const long ra_Cont // Value sf8 corresponds to 8 subframes, value sf16 corresponds to 16 subframes, and so on. // We add 2 * K2 because the timer runs from Msg2 transmission till Msg4 ACK reception ra->contention_resolution_timer = ((((int)ra_ContentionResolutionTimer + 1) * 8) << scs) + 2 * K2; - LOG_I(NR_MAC, + LOG_D(NR_MAC, "Starting RA Contention Resolution timer with %d ms + 2 * %d K2 (%d slots) duration\n", ((int)ra_ContentionResolutionTimer + 1) * 8, K2, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index d0b36a4603..d091d486ff 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -860,12 +860,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, // re-initialize ta update variables after RA procedure completion UE->UE_sched_ctrl.ta_frame = frameP; - LOG_I(NR_MAC, - "[gNB %d][RAPROC] PUSCH with TC_RNTI 0x%04x received correctly, " - "adding UE MAC Context RNTI 0x%04x\n", - gnb_mod_idP, - current_rnti, - ra->rnti); + LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frameP, slotP, current_rnti); NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl; if (ul_cqi != 0xff) { @@ -884,7 +879,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, ra->CellGroup->rlc_BearerToAddModList); nr_clear_ra_proc(ra); } else { - LOG_A(NR_MAC, "[RAPROC] RA-Msg3 received (sdu_lenP %d)\n", sdu_lenP); LOG_D(NR_MAC, "[RAPROC] Received Msg3:\n"); for (uint32_t k = 0; k < sdu_lenP; k++) { LOG_D(NR_MAC, "(%i): 0x%x\n", k, sduP[k]); From 4e7e8a6fa0c109b79cb919ea3f71c8d11cd009d1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 6 Aug 2024 19:21:10 +0200 Subject: [PATCH 08/33] Fix bug: correctly fill LCID in ue context setup resp Before this bug fix, when using F1, we get this warning: Constraint validation failed: LCID: constraint failed (/home/richie/openairinterface5g/cmake_targets/ran_build/build/openair2/F1AP/MESSAGES/F1AP_LCID.c:30) This is because (1) we don't actually store the LCID, then (2) we did not put it into the F1 ASN.1 structures. Fix both, to make this warning disappear. To actually print the full error message, increase the error buffer size. Also, for the future, to avoid guessing, print ASN.1 XML when we encounter a failed constraint validation. --- openair2/F1AP/f1ap_du_ue_context_management.c | 1 + openair2/F1AP/f1ap_encoder.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 5ab1c07d6c..6d9771f1f4 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -593,6 +593,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set F1AP_SRBs_Setup_Item_t *srbs_setup_item=&srbs_setup_item_ies->value.choice.SRBs_Setup_Item; /* sRBID */ srbs_setup_item->sRBID = resp->srbs_to_be_setup[i].srb_id; + srbs_setup_item->lCID = resp->srbs_to_be_setup[i].lcid; } } diff --git a/openair2/F1AP/f1ap_encoder.c b/openair2/F1AP/f1ap_encoder.c index 870dfd73fc..5de4ba43db 100644 --- a/openair2/F1AP/f1ap_encoder.c +++ b/openair2/F1AP/f1ap_encoder.c @@ -40,13 +40,13 @@ int f1ap_encode_pdu(F1AP_F1AP_PDU_t *pdu, uint8_t **buffer, uint32_t *length) { LOG_E(F1AP, "----------------- ASN1 ENCODER PRINT END----------------- \n"); } - char errbuf[128]; /* Buffer for error message */ + char errbuf[4096]; /* Buffer for error message */ size_t errlen = sizeof(errbuf); /* Size of the buffer */ int ret = asn_check_constraints(&asn_DEF_F1AP_F1AP_PDU, pdu, errbuf, &errlen); - /* assert(errlen < sizeof(errbuf)); // Guaranteed: you may rely on that */ if(ret) { - fprintf(stderr, "Constraint validation failed: %s\n", errbuf); + xer_fprint(stdout, &asn_DEF_F1AP_F1AP_PDU, pdu); + LOG_E(F1AP, "Constraint validation failed: %s\n", errbuf); } encoded = aper_encode_to_new_buffer(&asn_DEF_F1AP_F1AP_PDU, 0, pdu, (void **)buffer); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 9b5bd938ec..bb84a4793c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -233,7 +233,8 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .priority = priority}; nr_mac_add_lcid(&UE->UE_sched_ctrl, &c); - (*resp_srbs)[i] = *srb; + (*resp_srbs)[i].srb_id = srb->srb_id; + (*resp_srbs)[i].lcid = c.lcid; int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); DevAssert(ret == 0); From 31bad32b572ab4c08151d67b6411acd0b02416e9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Aug 2024 16:55:43 +0200 Subject: [PATCH 09/33] Reestablishment with RRC setup fallback: release old UE if applicable --- openair2/RRC/NR/rrc_gNB.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f9646468e0..14e84861a7 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1120,7 +1120,9 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, uint64_t random_value = 0; const char *scause = get_reestab_cause(req->reestablishmentCause); const long physCellId = req->ue_Identity.physCellId; - LOG_D(NR_RRC, "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", msg->crnti, physCellId, scause); + long ngap_cause = NGAP_CAUSE_RADIO_NETWORK_UNSPECIFIED; /* cause in case of NGAP release req */ + rrc_gNB_ue_context_t *ue_context_p = NULL; + LOG_I(NR_RRC, "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", msg->crnti, physCellId, scause); const nr_rrc_du_container_t *du = get_du_by_assoc_id(rrc, assoc_id); if (du == NULL) { @@ -1137,7 +1139,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, } rnti_t old_rnti = req->ue_Identity.c_RNTI; - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); + ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); if (ue_context_p == NULL) { LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); goto fallback_rrc_setup; @@ -1150,6 +1152,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, "RRC Reestablishment Request from different physCellId (%ld) than current physCellId (%d), fallback to RRC setup\n", physCellId, cell_info->nr_pci); + ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; /* 38.401 8.7: "If the UE accessed from a gNB-DU other than the original * one, the gNB-CU should trigger the UE Context Setup procedure". Let's * assume that the old DU will trigger a release request, also freeing the @@ -1168,6 +1171,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, if (!UE->as_security_active) { /* no active security context, need to restart entire connection */ LOG_E(NR_RRC, "UE requested Reestablishment without activated AS security\n"); + ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; goto fallback_rrc_setup; } @@ -1176,6 +1180,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, // SSB ARFCN and can't do reestablishment. handle it gracefully by doing // RRC setup procedure instead LOG_E(NR_RRC, "no MeasurementTimingConfiguration for this cell, cannot perform reestablishment\n"); + ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; goto fallback_rrc_setup; } @@ -1188,8 +1193,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, cu_remove_f1_ue_data(UE->rrc_ue_id); cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data); - LOG_I(NR_RRC, "Accept Reestablishment Request UE physCellId %ld cause %s\n", physCellId, scause); - rrc_gNB_generate_RRCReestablishment(ue_context_p, msg->du2cu_rrc_container, old_rnti, du); return; @@ -1197,6 +1200,10 @@ fallback_rrc_setup: fill_random(&random_value, sizeof(random_value)); random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ + /* request release of the "old" UE in case it exists */ + if (ue_context_p != NULL) + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(0, ue_context_p, NGAP_CAUSE_RADIO_NETWORK, ngap_cause); + rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); activate_srb(&new->ue_context, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); From 8d6b6676c51843f5f5e9aecc344245b15b504fbd Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 7 Aug 2024 16:50:35 +0200 Subject: [PATCH 10/33] Reorganize sequence of reestablishment checks Reorganize the sequence of checks done in reestablishment to make it more logical: - check conditions of request (correct C-RNTI) - check conditions of DU (has MIB/SIB1, MTC) - check the UE, and from which DU it comes This will also help to extend it towards reestablishment coming from different DUs in the case of handover. --- openair2/RRC/NR/rrc_gNB.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 14e84861a7..b884a2d808 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1130,6 +1130,13 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, return; } + // 3GPP TS 38.321 version 15.13.0 Section 7.1 Table 7.1-1: RNTI values + if (req->ue_Identity.c_RNTI < 0x1 || req->ue_Identity.c_RNTI > 0xffef) { + /* c_RNTI range error should not happen */ + LOG_E(NR_RRC, "NR_RRCReestablishmentRequest c_RNTI %04lx range error, fallback to RRC setup\n", req->ue_Identity.c_RNTI); + goto fallback_rrc_setup; + } + if (du->mib == NULL || du->sib1 == NULL) { /* we don't have MIB/SIB1 of the DU, and therefore cannot generate the * Reestablishment (as we would need the SSB's ARFCN, which we cannot @@ -1138,12 +1145,22 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, goto fallback_rrc_setup; } + if (du->mtc == NULL) { + // some UEs don't send MeasurementTimingConfiguration, so we don't know the + // SSB ARFCN and can't do reestablishment. handle it gracefully by doing + // RRC setup procedure instead + LOG_E(NR_RRC, "no MeasurementTimingConfiguration for this cell, cannot perform reestablishment\n"); + ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; + goto fallback_rrc_setup; + } + rnti_t old_rnti = req->ue_Identity.c_RNTI; ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); if (ue_context_p == NULL) { LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); goto fallback_rrc_setup; } + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; if (physCellId != cell_info->nr_pci) { @@ -1160,14 +1177,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, goto fallback_rrc_setup; } - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - // 3GPP TS 38.321 version 15.13.0 Section 7.1 Table 7.1-1: RNTI values - if (req->ue_Identity.c_RNTI < 0x1 || req->ue_Identity.c_RNTI > 0xffef) { - /* c_RNTI range error should not happen */ - LOG_E(NR_RRC, "NR_RRCReestablishmentRequest c_RNTI %04lx range error, fallback to RRC setup\n", req->ue_Identity.c_RNTI); - goto fallback_rrc_setup; - } - if (!UE->as_security_active) { /* no active security context, need to restart entire connection */ LOG_E(NR_RRC, "UE requested Reestablishment without activated AS security\n"); @@ -1175,15 +1184,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, goto fallback_rrc_setup; } - if (du->mtc == NULL) { - // some UEs don't send MeasurementTimingConfiguration, so we don't know the - // SSB ARFCN and can't do reestablishment. handle it gracefully by doing - // RRC setup procedure instead - LOG_E(NR_RRC, "no MeasurementTimingConfiguration for this cell, cannot perform reestablishment\n"); - ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; - goto fallback_rrc_setup; - } - /* TODO: start timer in ITTI and drop UE if it does not come back */ // update with new RNTI, and update secondary UE association From ea171c75c0b941dc982e1e932a4c5a267705e038 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 31 May 2024 12:25:51 +0200 Subject: [PATCH 11/33] nr_timer: consistently pass by ref, rename to nr_timer_is_active() Pass consistently the NR_timer_t object through a pointer. Since we have to modify all occurrences of is_nr_timer_active(), we use that occasion and rename that function to nr_timer_is_active() to make it consistent with all other functions, starting with nr_timer. --- common/utils/nr/nr_common.c | 16 ++++++++-------- common/utils/nr/nr_common.h | 6 +++--- common/utils/nr/tests/test_nr_common.cpp | 8 ++++---- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 4 ++-- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 4 ++-- openair2/RRC/NR_UE/rrc_UE.c | 8 ++++---- openair2/RRC/NR_UE/rrc_timers_and_constants.c | 14 +++++++------- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index c1ed6c7546..f851c26eee 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -1161,9 +1161,9 @@ void nr_timer_stop(NR_timer_t *timer) timer->counter = 0; } -bool is_nr_timer_active(NR_timer_t timer) +bool nr_timer_is_active(const NR_timer_t *timer) { - return timer.active; + return timer->active; } bool nr_timer_tick(NR_timer_t *timer) @@ -1173,23 +1173,23 @@ bool nr_timer_tick(NR_timer_t *timer) timer->counter += timer->step; if (timer->target == UINT_MAX) // infinite target, never expires return false; - expired = nr_timer_expired(*timer); + expired = nr_timer_expired(timer); if (expired) timer->active = false; } return expired; } -bool nr_timer_expired(NR_timer_t timer) +bool nr_timer_expired(const NR_timer_t *timer) { - if (timer.target == UINT_MAX) // infinite target, never expires + if (timer->target == UINT_MAX) // infinite target, never expires return false; - return (timer.counter >= timer.target); + return timer->counter >= timer->target; } -uint32_t nr_timer_elapsed_time(NR_timer_t timer) +uint32_t nr_timer_elapsed_time(const NR_timer_t *timer) { - return timer.counter; + return timer->counter; } void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t step) diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index fcefa29461..0f29492181 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -163,19 +163,19 @@ void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t ste * @param timer Timer to be checked * @return Indication if the timer is expired or not */ -bool nr_timer_expired(NR_timer_t timer); +bool nr_timer_expired(const NR_timer_t *timer); /** * @brief To check if a timer is active * @param timer Timer to be checked * @return Indication if the timer is active or not */ -bool is_nr_timer_active(NR_timer_t timer); +bool nr_timer_is_active(const NR_timer_t *timer); /** * @brief To return how much time has passed since start of timer * @param timer Timer to be checked * @return Time passed since start of timer */ -uint32_t nr_timer_elapsed_time(NR_timer_t timer); +uint32_t nr_timer_elapsed_time(const NR_timer_t *timer); extern const nr_bandentry_t nr_bandtable[]; diff --git a/common/utils/nr/tests/test_nr_common.cpp b/common/utils/nr/tests/test_nr_common.cpp index fede91b8ee..c780736a51 100644 --- a/common/utils/nr/tests/test_nr_common.cpp +++ b/common/utils/nr/tests/test_nr_common.cpp @@ -29,13 +29,13 @@ TEST(nr_common, nr_timer) { NR_timer_t timer; nr_timer_setup(&timer, 10, 1); nr_timer_start(&timer); - EXPECT_TRUE(is_nr_timer_active(timer)); - EXPECT_FALSE(nr_timer_expired(timer)); + EXPECT_TRUE(nr_timer_is_active(&timer)); + EXPECT_FALSE(nr_timer_expired(&timer)); for (auto i = 0; i < 10; i++) { nr_timer_tick(&timer); } - EXPECT_FALSE(is_nr_timer_active(timer)); - EXPECT_TRUE(nr_timer_expired(timer)); + EXPECT_FALSE(nr_timer_is_active(&timer)); + EXPECT_TRUE(nr_timer_expired(&timer)); } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index c26e8a5629..c52a67c5a2 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -790,7 +790,7 @@ void nr_ue_get_rach(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, uint8_t gNB } } - if (is_nr_timer_active(ra->contention_resolution_timer)) { + if (nr_timer_is_active(&ra->contention_resolution_timer)) { nr_ue_contention_resolution(mac, CC_id, frame, nr_slot_tx, prach_resources); } } @@ -851,7 +851,7 @@ void nr_ue_contention_resolution(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame { RA_config_t *ra = &mac->ra; - if (nr_timer_expired(ra->contention_resolution_timer)) { + if (nr_timer_expired(&ra->contention_resolution_timer)) { ra->t_crnti = 0; nr_timer_stop(&ra->contention_resolution_timer); // Signal PHY to quit RA procedure diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index ac743c0f60..ccfa861587 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2543,7 +2543,7 @@ int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_Schedu sr_id); // todo // TODO check if the PUCCH resource for the SR transmission occasion does not overlap with a UL-SCH resource - if (!sr_info->pending || is_nr_timer_active(sr_info->prohibitTimer)) + if (!sr_info->pending || nr_timer_is_active(&sr_info->prohibitTimer)) return 0; if (sr_info->counter < sr_info->maxTransmissions) { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 557a393ce2..b66ff3203c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1297,7 +1297,7 @@ static void nr_update_sr(NR_UE_MAC_INST_t *mac) // if a Regular BSR has been triggered and logicalChannelSR-DelayTimer is not running if (((sched_info->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0) - || is_nr_timer_active(sched_info->sr_DelayTimer)) + || nr_timer_is_active(&sched_info->sr_DelayTimer)) return; nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, sched_info->regularBSR_trigger_lcid); @@ -1527,7 +1527,7 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); int32_t bj = sched_info->Bj; if (lc_info->pbr < UINT_MAX) { - uint32_t slots_elapsed = nr_timer_elapsed_time(sched_info->Bj_timer); // slots elapsed since Bj was last incremented + uint32_t slots_elapsed = nr_timer_elapsed_time(&sched_info->Bj_timer); // slots elapsed since Bj was last incremented // it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s uint32_t pbr_ms = lc_info->pbr / 1000; bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index eb5113ccee..fc3693ea7b 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -479,7 +479,7 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc, // Actions following cell selection while T311 is running NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; - if (is_nr_timer_active(timers->T311)) { + if (nr_timer_is_active(&timers->T311)) { nr_timer_stop(&timers->T311); rrc->ra_trigger = RRC_CONNECTION_REESTABLISHMENT; @@ -1695,7 +1695,7 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc, void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded) { NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; - if (ra_succeeded && is_nr_timer_active(timers->T304)) { + if (ra_succeeded && nr_timer_is_active(&timers->T304)) { // successful Random Access procedure triggered by reconfigurationWithSync nr_timer_stop(&timers->T304); // TODO handle the rest of procedures as described in 5.3.5.3 for when @@ -2218,14 +2218,14 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, } } if (!waitTime) { - if (is_nr_timer_active(tac->T302)) { + if (nr_timer_is_active(&tac->T302)) { nr_timer_stop(&tac->T302); // TODO barring alleviation as in 5.3.14.4 // not implemented LOG_E(NR_RRC,"Go to IDLE. Barring alleviation not implemented\n"); } } - if (is_nr_timer_active(tac->T390)) { + if (nr_timer_is_active(&tac->T390)) { nr_timer_stop(&tac->T390); // TODO barring alleviation as in 5.3.14.4 // not implemented diff --git a/openair2/RRC/NR_UE/rrc_timers_and_constants.c b/openair2/RRC/NR_UE/rrc_timers_and_constants.c index 70a467691b..9e734a3188 100644 --- a/openair2/RRC/NR_UE/rrc_timers_and_constants.c +++ b/openair2/RRC/NR_UE/rrc_timers_and_constants.c @@ -560,7 +560,7 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac, { if (sync_msg == IN_SYNC) { tac->N310_cnt = 0; - if (is_nr_timer_active(tac->T310)) { + if (nr_timer_is_active(&tac->T310)) { tac->N311_cnt++; // Upon receiving N311 consecutive "in-sync" indications if (tac->N311_cnt >= tac->N311_k) { @@ -573,12 +573,12 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac, else { // OUT_OF_SYNC tac->N311_cnt = 0; - if(is_nr_timer_active(tac->T300) || - is_nr_timer_active(tac->T301) || - is_nr_timer_active(tac->T304) || - is_nr_timer_active(tac->T310) || - is_nr_timer_active(tac->T311) || - is_nr_timer_active(tac->T319)) + if(nr_timer_is_active(&tac->T300) || + nr_timer_is_active(&tac->T301) || + nr_timer_is_active(&tac->T304) || + nr_timer_is_active(&tac->T310) || + nr_timer_is_active(&tac->T311) || + nr_timer_is_active(&tac->T319)) return; tac->N310_cnt++; // upon receiving N310 consecutive "out-of-sync" indications From 303e724845c3abf34d3abc736ef83807138d97f1 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 2 Aug 2024 15:14:15 +0100 Subject: [PATCH 12/33] Always set firstActive/defaultBWP Always set the firstActive and defaultBWP in the initial cellGroupConfig. This is necessary to make the Quectel accept the handover RRCReconfiguration; it seems that this also works reliably in normal connection set up, so we can add it. --- openair2/RRC/NR/nr_rrc_config.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index e5f0c295b5..5631da4c0e 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -2805,6 +2805,8 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, && servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count > 0) { n_dl_bwp = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count; } + int default_dl_bwp = 0; + int first_active_dl_bwp = 0; if (n_dl_bwp > 0) { SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList)); @@ -2813,15 +2815,13 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, config_downlinkBWP(bwp, scc, servingcellconfigdedicated, NULL, 0, false, bwp_loop, true); asn1cSeqAdd(&SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list, bwp); } - SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = - calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id)); - *SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = - servingcellconfigdedicated->firstActiveDownlinkBWP_Id ? *servingcellconfigdedicated->firstActiveDownlinkBWP_Id : 1; - SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = - calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id)); - *SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = - servingcellconfigdedicated->defaultDownlinkBWP_Id ? *servingcellconfigdedicated->defaultDownlinkBWP_Id : 1; + const NR_BWP_Id_t *firstActiveDownlinkBWP_Id = servingcellconfigdedicated->firstActiveDownlinkBWP_Id; + first_active_dl_bwp = firstActiveDownlinkBWP_Id ? *firstActiveDownlinkBWP_Id : 1; + const NR_BWP_Id_t *defaultDownlinkBWP_Id = servingcellconfigdedicated->defaultDownlinkBWP_Id; + default_dl_bwp = defaultDownlinkBWP_Id ? *defaultDownlinkBWP_Id : 1; } + asn1cCallocOne(SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id, first_active_dl_bwp); + asn1cCallocOne(SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id, default_dl_bwp); // Uplink BWPs int n_ul_bwp = 0; @@ -2830,6 +2830,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, && servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count > 0) { n_ul_bwp = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; } + int first_active_ul_bwp = 0; if (n_ul_bwp > 0) { uplinkConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*uplinkConfig->uplinkBWP_ToAddModList)); for (int bwp_loop = 0; bwp_loop < n_ul_bwp; bwp_loop++) { @@ -2837,11 +2838,10 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, config_uplinkBWP(ubwp, bwp_loop, true, uid, configuration, servingcellconfigdedicated, scc, NULL); asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ubwp); } - uplinkConfig->firstActiveUplinkBWP_Id = calloc(1, sizeof(*uplinkConfig->firstActiveUplinkBWP_Id)); - *uplinkConfig->firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id - ? *servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id - : 1; + const NR_BWP_Id_t *firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id; + first_active_ul_bwp = firstActiveUplinkBWP_Id ? *firstActiveUplinkBWP_Id : 1; } + asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_ul_bwp); SpCellConfig->spCellConfigDedicated->csi_MeasConfig = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig)); SpCellConfig->spCellConfigDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; From e63232576e2088e47bf5fdd26932803e5f0bfd9d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 6 Aug 2024 13:50:22 +0200 Subject: [PATCH 13/33] RRC stats: print DU's SSB ARFCN --- openair2/RRC/NR/rrc_gNB_du.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index b24e6f594c..43b657d91e 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -501,7 +501,7 @@ void dump_du_info(const gNB_RRC_INST *rrc, FILE *f) fprintf(f, "assoc_id %d", du->assoc_id); } const f1ap_served_cell_info_t *info = &sr->cell[0].info; - fprintf(f, ": nrCellID %ld, PCI %d\n", info->nr_cellid, info->nr_pci); + fprintf(f, ": nrCellID %ld, PCI %d, SSB ARFCN %d\n", info->nr_cellid, info->nr_pci, get_ssb_arfcn(du)); if (info->mode == F1AP_MODE_TDD) { const f1ap_nr_frequency_info_t *fi = &info->tdd.freqinfo; From e01957e89088304969345861762b5d0195fdfc18 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 3 Jun 2024 11:01:50 +0200 Subject: [PATCH 14/33] Remove RRC status: it is not needed --- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB.c | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index a9234ed5bd..4159362921 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -284,7 +284,6 @@ typedef struct gNB_RRC_UE_s { NR_CipheringAlgorithm_t ciphering_algorithm; e_NR_IntegrityProtAlgorithm integrity_algorithm; - NR_UE_STATE_t StatusRrc; rnti_t rnti; uint64_t random_ue_identity; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b884a2d808..7d7f40e9df 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -477,7 +477,6 @@ static void rrc_gNB_process_RRCSetupComplete(const protocol_ctxt_t *const ctxt_p LOG_A(NR_RRC, "UE %d Processing NR_RRCSetupComplete from UE\n", ue_context_pP->ue_context.rrc_ue_id); ue_context_pP->ue_context.Srb[1].Active = 1; ue_context_pP->ue_context.Srb[2].Active = 0; - ue_context_pP->ue_context.StatusRrc = NR_RRC_CONNECTED; AssertFatal(ctxt_pP->rntiMaybeUEid == ue_context_pP->ue_context.rrc_ue_id, "logic bug: inconsistent IDs, must use CU UE ID!\n"); rrc_gNB_send_NGAP_NAS_FIRST_REQ(ctxt_pP, ue_context_pP, rrcSetupComplete); @@ -935,7 +934,6 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co int i = 0; ue_p->xids[xid] = RRC_ACTION_NONE; - ue_p->StatusRrc = NR_RRC_CONNECTED; ue_p->Srb[1].Active = 1; @@ -2262,20 +2260,6 @@ static void print_rrc_meas(FILE *f, const NR_MeasResults_t *measresults) } } -static const char *get_rrc_connection_status_text(NR_UE_STATE_t state) -{ - switch (state) { - case NR_RRC_INACTIVE: return "inactive"; - case NR_RRC_IDLE: return "idle"; - case NR_RRC_SI_RECEIVED: return "SI-received"; - case NR_RRC_CONNECTED: return "connected"; - case NR_RRC_RECONFIGURED: return "reconfigured"; - case NR_RRC_HO_EXECUTION: return "HO-execution"; - default: AssertFatal(false, "illegal RRC state %d\n", state); return "illegal"; - } - return "illegal"; -} - static const char *get_pdusession_status_text(pdu_session_status_t status) { switch (status) { @@ -2323,7 +2307,6 @@ static void write_rrc_stats(const gNB_RRC_INST *rrc) time_t last_seen = now - ue_ctxt->last_seen; fprintf(f, " last RRC activity: %ld seconds ago\n", last_seen); - fprintf(f, " RRC status %s\n", get_rrc_connection_status_text(ue_ctxt->StatusRrc)); if (ue_ctxt->nb_of_pdusessions == 0) fprintf(f, " (no PDU sessions)\n"); From 125210fa1e523826c15271f5dfaa01730c6b452e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 6 Aug 2024 13:49:45 +0200 Subject: [PATCH 15/33] RRC: Correct some logs --- openair2/RRC/NR/rrc_gNB.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7d7f40e9df..813bbd0310 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1233,11 +1233,11 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, switch (event_triggered->eventId.present) { case NR_EventTriggerConfig__eventId_PR_eventA2: - LOG_I(NR_RRC, "\nHO LOG: Event A2 (Serving becomes worse than threshold)\n"); + LOG_I(NR_RRC, "HO LOG: Event A2 (Serving becomes worse than threshold)\n"); break; case NR_EventTriggerConfig__eventId_PR_eventA3: { - LOG_I(NR_RRC, "\nHO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n"); + LOG_I(NR_RRC, "HO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n"); const NR_MeasResults_t *measResults = &measurementReport->criticalExtensions.choice.measurementReport->measResults; for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) { @@ -1272,7 +1272,7 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, } LOG_I(NR_RRC, - "HO LOG: Measurement Report has came for the neighbour: %d with RSRP: %d\n", + "HO LOG: Measurement Report for the neighbour %d with RSRP: %d\n", neighbourCellId, neighbourCellRSRP); From 94258b0fb95a74a9ddf5957fa7c845d546eeb18e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 14:46:30 +0200 Subject: [PATCH 16/33] Remove unused fields of DRB --- openair2/RRC/NR/nr_rrc_defs.h | 4 ---- openair2/RRC/NR/rrc_gNB.c | 1 - openair2/RRC/NR/rrc_gNB_radio_bearers.c | 3 --- 3 files changed, 8 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 4159362921..f4d217c8cc 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -202,11 +202,7 @@ typedef struct f1u_tunnel_s { typedef struct drb_s { int status; - int defaultDRBid; int drb_id; - int reestablishPDCP; - int recoverPDCP; - int daps_Config_r16; struct cnAssociation_s { int present; int eps_BearerIdentity; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 813bbd0310..976f11bd72 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -345,7 +345,6 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) if (ue->established_drbs[i].status != DRB_INACTIVE) { DRB_config = generateDRB_ASN1(&ue->established_drbs[i]); if (reestablish) { - ue->established_drbs[i].reestablishPDCP = NR_DRB_ToAddMod__reestablishPDCP_true; asn1cCallocOne(DRB_config->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true); } asn1cSeqAdd(&DRB_configList->list, DRB_config); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 205a58fc36..10f16cb030 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -96,10 +96,7 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, est_drb->status = DRB_ACTIVE; est_drb->drb_id = drb_id; - est_drb->reestablishPDCP = -1; - est_drb->recoverPDCP = -1; est_drb->cnAssociation.sdap_config.defaultDRB = true; - est_drb->defaultDRBid = drb_id; /* SDAP Configuration */ est_drb->cnAssociation.present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config; From d2073d924e1fd5799bf4af1e63fa83e623adc29b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 18:45:15 +0200 Subject: [PATCH 17/33] Remove unused information from PDU session --- openair2/COMMON/ngap_messages_types.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index faeb11d377..861f5e6d2c 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -278,8 +278,6 @@ typedef struct pdusession_s { transport_layer_addr_t upf_addr; /* Outgoing (UL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ uint32_t gtp_teid; - /* Stores the DRB ID of the DRBs used by this PDU Session */ - uint8_t used_drbs[MAX_DRBS_PER_UE]; /* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ uint32_t gNB_teid_N3; transport_layer_addr_t gNB_addr_N3; From 44d427bf7b6493d3bba892edf6fbd5dede808c9f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 23 Jul 2024 17:32:29 +0200 Subject: [PATCH 18/33] Rename RRC_BUF_SIZE for 5G to increase size A maximum RRC buffer size of 1024 might be very small. We should increase it, but then the 5G RRC_BUF_SIZE does conflict with other definitions. To make it unique, also rename to NR_RRC_BUF_SIZE. --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 4 ++-- openair2/RRC/NR/rrc_gNB.c | 30 ++++++++++++++--------------- openair2/RRC/NR_UE/rrc_UE.c | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 3849e157c9..13f704b2c7 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1368,7 +1368,7 @@ int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi) LOG_D(NR_RRC, "[gNB %d] do_Paging paging_record: PagingRecordList.count %d\n", Mod_id, c1->choice.paging->pagingRecordList->list.count); asn_enc_rval_t enc_rval = uper_encode_to_buffer( - &asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, RRC_BUF_SIZE); + &asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, NR_RRC_BUF_SIZE); if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { xer_fprint(stdout, &asn_DEF_NR_PCCH_Message, (void *)&pcch_msg); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index f4d217c8cc..0b246aab54 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -115,7 +115,7 @@ typedef enum { #define MAX_MEAS_ID 7 #define PAYLOAD_SIZE_MAX 1024 -#define RRC_BUF_SIZE 1024 +#define NR_RRC_BUF_SIZE 4096 #define UNDEF_SECURITY_MODE 0xff #define NO_SECURITY_MODE 0x20 @@ -156,7 +156,7 @@ typedef struct HANDOVER_INFO_NR_s { //AS_Config_t as_config; /* these two parameters are taken from 36.331 section 10.2.2: HandoverPreparationInformation-r8-IEs */ //AS_Context_t as_context; /* They are mandatory for HO */ - uint8_t buf[RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */ + uint8_t buf[NR_RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */ int size; /* size of above message in bytes */ } NR_HANDOVER_INFO; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 976f11bd72..41b71af08a 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -547,13 +547,13 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c ue_p->measConfig = measconfig; - uint8_t buffer[RRC_BUF_SIZE] = {0}; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false); NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); int size = do_RRCReconfiguration(ue_p, buffer, - RRC_BUF_SIZE, + NR_RRC_BUF_SIZE, xid, SRBs, DRBs, @@ -674,10 +674,10 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( } NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); - uint8_t buffer[RRC_BUF_SIZE]; + uint8_t buffer[NR_RRC_BUF_SIZE]; int size = do_RRCReconfiguration(ue_p, buffer, - RRC_BUF_SIZE, + NR_RRC_BUF_SIZE, xid, NULL, DRBs, @@ -740,10 +740,10 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( LOG_W(NR_RRC,"dedlicated NAS list is empty\n"); } - uint8_t buffer[RRC_BUF_SIZE] = {0}; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; int size = do_RRCReconfiguration(ue_p, buffer, - RRC_BUF_SIZE, + NR_RRC_BUF_SIZE, xid, NULL, NULL, @@ -861,12 +861,12 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context module_id_t module_id = 0; gNB_RRC_INST *rrc = RC.nrrrc[module_id]; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - uint8_t buffer[RRC_BUF_SIZE] = {0}; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; uint8_t xid = rrc_gNB_get_next_transaction_identifier(module_id); ue_p->xids[xid] = RRC_REESTABLISH; const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; uint32_t ssb_arfcn = get_ssb_arfcn(du); - int size = do_RRCReestablishment(ue_context_pP, buffer, RRC_BUF_SIZE, xid, cell_info->nr_pci, ssb_arfcn); + int size = do_RRCReestablishment(ue_context_pP, buffer, NR_RRC_BUF_SIZE, xid, cell_info->nr_pci, ssb_arfcn); LOG_I(NR_RRC, "[RAPROC] UE %04x Logical Channel DL-DCCH, Generating NR_RRCReestablishment (bytes %d)\n", ue_p->rnti, size); @@ -984,10 +984,10 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; - uint8_t buffer[RRC_BUF_SIZE] = {0}; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; int size = do_RRCReconfiguration(ue_p, buffer, - RRC_BUF_SIZE, + NR_RRC_BUF_SIZE, new_xid, SRBs, DRBs, @@ -1028,8 +1028,8 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP, *masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = ul_bwp_id; } - uint8_t buffer[RRC_BUF_SIZE]; - int size = do_RRCReconfiguration(ue_p, buffer, RRC_BUF_SIZE, xid, NULL, NULL, NULL, NULL, NULL, NULL, masterCellGroup); + uint8_t buffer[NR_RRC_BUF_SIZE]; + int size = do_RRCReconfiguration(ue_p, buffer, NR_RRC_BUF_SIZE, xid, NULL, NULL, NULL, NULL, NULL, NULL, masterCellGroup); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size); @@ -2595,8 +2595,8 @@ rrc_gNB_generate_RRCRelease( ) //----------------------------------------------------------------------------- { - uint8_t buffer[RRC_BUF_SIZE] = {0}; - int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id)); + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; + int size = do_NR_RRCRelease(buffer, NR_RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id)); LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate RRCRelease (bytes %d)\n", @@ -2628,7 +2628,7 @@ int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint uint32_t N; /* N: min(T,nB). total count of PF in one DRX cycle */ uint32_t Ns = 0; /* Ns: max(1,nB/T) */ uint32_t T; /* DRX cycle */ - uint8_t buffer[RRC_BUF_SIZE]; + uint8_t buffer[NR_RRC_BUF_SIZE]; /* get default DRX cycle from configuration */ Tc = sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config.defaultPagingCycle; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index fc3693ea7b..477df28703 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -2130,7 +2130,7 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, nr_SecondaryCellGroup_buffer, nr_SecondaryCellGroup_size); process_nsa_message(NR_UE_rrc_inst, nr_RadioBearerConfigX_r15, nr_RadioBearer_buffer, nr_RadioBearer_size); LOG_I(NR_RRC, "Calling do_NR_RRCReconfigurationComplete. t_id %ld \n", t_id); - uint8_t buffer[RRC_BUF_SIZE]; + uint8_t buffer[NR_RRC_BUF_SIZE]; size_t size = do_NR_RRCReconfigurationComplete_for_nsa(buffer, sizeof(buffer), t_id); nsa_sendmsg_to_lte_ue(buffer, size, NR_RRC_CONFIG_COMPLETE_REQ); break; @@ -2138,7 +2138,7 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l case OAI_TUN_IFACE_NSA: { LOG_I(NR_RRC, "We got an OAI_TUN_IFACE_NSA!!\n"); - char cmd_line[RRC_BUF_SIZE]; + char cmd_line[NR_RRC_BUF_SIZE]; memcpy(cmd_line, msg_buffer, sizeof(cmd_line)); LOG_D(NR_RRC, "Command line: %s\n", cmd_line); if (background_system(cmd_line) != 0) From 29d8e3ce3afa890caeff8c3bb0f52a6b06cb7b9e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jul 2024 13:51:02 +0200 Subject: [PATCH 19/33] Remove unused defines and structures --- openair2/RRC/NR/nr_rrc_common.h | 8 -------- openair2/RRC/NR/nr_rrc_defs.h | 25 ------------------------- 2 files changed, 33 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_common.h b/openair2/RRC/NR/nr_rrc_common.h index e1ff2e703e..305013ecf4 100644 --- a/openair2/RRC/NR/nr_rrc_common.h +++ b/openair2/RRC/NR/nr_rrc_common.h @@ -26,17 +26,9 @@ #include #include -#define NR_RRC_HEADER_SIZE_MAX 64 -#define NR_RRC_BUFFER_SIZE_MAX 1024 #define NR_NUM_SRB 4 /* Number of Signalling Radio Bearers according to clause 4.2.2 of 3GPP TS 38.331 */ #define NR_K_KEY_SIZE 16 /* K keys have 128 bits length */ -typedef struct { - char Payload[NR_RRC_BUFFER_SIZE_MAX]; - char Header[NR_RRC_HEADER_SIZE_MAX]; - uint16_t payload_size; -} NR_RRC_BUFFER; - typedef enum UE_STATE_NR_e { NR_RRC_INACTIVE=0, NR_RRC_IDLE, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 0b246aab54..8ade5409e0 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -88,15 +88,6 @@ #define NR_RRC_RECONFIGURATION_DELAY_MS 10 #define NR_RRC_BWP_SWITCHING_DELAY_MS 6 -// 3GPP TS 38.133 - Section 8 - Table 8.2.1.2.7-2: Parameters which cause interruption other than SCS -// This table was recently added to 3GPP. It shows that changing the parameters locationAndBandwidth, nrofSRS-Ports or -// maxMIMO-Layers-r16 causes an interruption. This parameter is not yet being used in code, but has been placed here -// for future reference. -#define NR_OF_SRS_PORTS_SWITCHING_DELAY_MS 30 - -#define NR_UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! -#define NR_UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1 - typedef enum { NR_RRC_OK=0, NR_RRC_ConnSetup_failed, @@ -105,16 +96,10 @@ typedef enum { NR_RRC_HO_STARTED } NR_RRC_status_t; -#define RRM_FREE(p) if ( (p) != NULL) { free(p) ; p=NULL ; } -#define RRM_MALLOC(t,n) (t *) malloc16( sizeof(t) * n ) -#define RRM_CALLOC(t,n) (t *) malloc16( sizeof(t) * n) -#define RRM_CALLOC2(t,s) (t *) malloc16( s ) - #define MAX_MEAS_OBJ 7 #define MAX_MEAS_CONFIG 7 #define MAX_MEAS_ID 7 -#define PAYLOAD_SIZE_MAX 1024 #define NR_RRC_BUF_SIZE 4096 #define UNDEF_SECURITY_MODE 0xff #define NO_SECURITY_MODE 0x20 @@ -129,14 +114,6 @@ typedef struct UE_S_TMSI_NR_s { uint32_t fiveg_tmsi; } __attribute__ ((__packed__)) NR_UE_S_TMSI; - -typedef enum nr_e_rab_satus_e { - NR_E_RAB_STATUS_NEW, - NR_E_RAB_STATUS_DONE, // from the gNB perspective - NR_E_RAB_STATUS_ESTABLISHED, // get the reconfigurationcomplete form UE - NR_E_RAB_STATUS_FAILED, -} nr_e_rab_status_t; - typedef struct nr_e_rab_param_s { e_rab_t param; uint8_t status; @@ -160,8 +137,6 @@ typedef struct HANDOVER_INFO_NR_s { int size; /* size of above message in bytes */ } NR_HANDOVER_INFO; -#define NR_RRC_BUFFER_SIZE sizeof(RRC_BUFFER_NR) - typedef struct nr_rrc_guami_s { uint16_t mcc; uint16_t mnc; From d00ac2031cc84b0ee3fb4d65933ee017e301c91a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 14:50:44 +0200 Subject: [PATCH 20/33] Correct F1-U TEID variable names, simplify code In e1_send_bearer_updates(), we send the DL (DU) TEID and address to the CU-UP. Therefore, correct the variable names to reflect that the F1-U information pertains to the DU. Also, move the tunnel info update function f1u_dl_gtp_update() to a more prominent place, and take the pointer to the struct containing the "interesting" information. --- openair2/RRC/NR/nr_rrc_defs.h | 12 ++++++------ openair2/RRC/NR/rrc_gNB.c | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 8ade5409e0..234c42daaf 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -169,10 +169,10 @@ typedef struct pdu_session_param_s { * @brief F1-U tunnel configuration */ typedef struct f1u_tunnel_s { - /* Downlink F1-U Tunnel Endpoint Identifier (CU-UP/DU) */ - uint32_t cuup_teid_f1u; - /* DL F1-U Transport Layer */ - transport_layer_addr_t cuup_addr_f1u; + /* F1-U Tunnel Endpoint Identifier (on DU side) */ + uint32_t teid; + /* Downlink F1-U Transport Layer (on DU side) */ + transport_layer_addr_t addr; } f1u_tunnel_t; typedef struct drb_s { @@ -203,8 +203,8 @@ typedef struct drb_s { int cipheringDisabled; } ext1; } pdcp_config; - // F1-U - f1u_tunnel_t f1u_tunnel_config; + // F1-U Downlink Tunnel Config (on DU side) + f1u_tunnel_t du_tunnel_config; } drb_t; typedef enum { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 41b71af08a..2b0d45ed5a 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -828,8 +828,8 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) drb_e1->id = drb_id; drb_e1->numDlUpParam = 1; drb_t *drbs = &ue_p->established_drbs[drb_id]; - memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drbs->f1u_tunnel_config.cuup_addr_f1u.buffer, sizeof(uint8_t) * 4); - drb_e1->DlUpParamList[0].teId = drbs->f1u_tunnel_config.cuup_teid_f1u; + memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drbs->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb_e1->DlUpParamList[0].teId = drbs->du_tunnel_config.teid; /* PDCP configuration */ bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config; drb_t *rrc_drb = get_drb(ue_p, drb_id); @@ -1868,15 +1868,15 @@ static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to /** * @brief Store F1-U DL TL and TEID in RRC */ -static void f1u_gtp_update(f1u_tunnel_t *f1u, const f1ap_drb_to_be_setup_t *drb_f1) +static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p) { - f1u->cuup_teid_f1u = drb_f1->up_dl_tnl[0].teid; - memcpy(&f1u->cuup_addr_f1u.buffer, &drb_f1->up_dl_tnl[0].tl_address, sizeof(uint8_t) * 4); - f1u->cuup_addr_f1u.length = sizeof(in_addr_t); + f1u->teid = p->teid; + memcpy(&f1u->addr.buffer, &p->tl_address, sizeof(uint8_t) * 4); + f1u->addr.length = sizeof(in_addr_t); } /* \brief use list of DRBs and send the corresponding bearer update message via - * E1 to the CU of this UE */ + * E1 to the CU of this UE. Also updates TEID info internally */ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) { // we assume the same UE ID in CU-UP and CU-CP @@ -1896,7 +1896,7 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f DevAssert(pdu_e1 != NULL); pdu_e1->sessionId = pdu_ue->param.pdusession_id; DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; - f1u_gtp_update(&UE->established_drbs[drb_f1->drb_id].f1u_tunnel_config, drb_f1); + f1u_dl_gtp_update(&UE->established_drbs[drb_f1->drb_id].du_tunnel_config, &drb_f1->up_dl_tnl[0]); /* Fill E1 bearer context modification */ fill_e1_bearer_modif(drb_e1, drb_f1); pdu_e1->numDRB2Modify += 1; From 605dfa0142d90484db4751aa06a6c9c0d86de450 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 17:54:26 +0200 Subject: [PATCH 21/33] Refactor: Store DU's DRB TEID/address through separate function A follow-up commit refactors the filling of information of DRBs to set up in a separate function (to be reused for handover later). Hence, we cannot store the DRB TEID/address in the same functions, because it is a logically separate step, and might not always be available. --- openair2/RRC/NR/rrc_gNB.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2b0d45ed5a..3d28a9fdaa 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1875,6 +1875,20 @@ static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p) f1u->addr.length = sizeof(in_addr_t); } +/** + * @brief Update DRB TEID information in RRC storage from received DRB list + */ +static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_RRC_UE_t *ue) +{ + for (int i = 0; i < n; i++) { + const f1ap_drb_to_be_setup_t *drb_f1 = &drbs[i]; + AssertFatal(drb_f1->up_dl_tnl_length == 1, "can handle only one UP param\n"); + AssertFatal(drb_f1->drb_id < MAX_DRBS_PER_UE, "illegal DRB ID %ld\n", drb_f1->drb_id); + drb_t *drb = get_drb(ue, drb_f1->drb_id); + f1u_dl_gtp_update(&drb->du_tunnel_config, &drb_f1->up_dl_tnl[0]); + } +} + /* \brief use list of DRBs and send the corresponding bearer update message via * E1 to the CU of this UE. Also updates TEID info internally */ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) @@ -1896,7 +1910,6 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f DevAssert(pdu_e1 != NULL); pdu_e1->sessionId = pdu_ue->param.pdusession_id; DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; - f1u_dl_gtp_update(&UE->established_drbs[drb_f1->drb_id].du_tunnel_config, &drb_f1->up_dl_tnl[0]); /* Fill E1 bearer context modification */ fill_e1_bearer_modif(drb_e1, drb_f1); pdu_e1->numDRB2Modify += 1; @@ -1946,6 +1959,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance /* Note: we would ideally check that SRB2 is acked, but at least LiteOn DU * seems buggy and does not ack, so simply check that locally we activated */ AssertFatal(UE->Srb[1].Active && UE->Srb[2].Active, "SRBs 1 and 2 must be active during DRB Establishment"); + store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE); e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); } @@ -2023,6 +2037,7 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i gNB_RRC_UE_t *UE = &ue_context_p->ue_context; if (resp->drbs_to_be_setup_length > 0) { + store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE); e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); } From e7eb1b1c3bda680b1ee94c2afa9b844b6d81e138 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 17:52:07 +0200 Subject: [PATCH 22/33] Store DRB UL TEID information at RRC To be used later in the case of handover. --- openair2/RRC/NR/nr_rrc_defs.h | 2 ++ openair2/RRC/NR/rrc_gNB.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 234c42daaf..de4bd5f5ec 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -205,6 +205,8 @@ typedef struct drb_s { } pdcp_config; // F1-U Downlink Tunnel Config (on DU side) f1u_tunnel_t du_tunnel_config; + // F1-U Uplink Tunnel Config (on CU-UP side) + f1u_tunnel_t cuup_tunnel_config; } drb_t; typedef enum { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 3d28a9fdaa..4e5593e8b5 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1889,6 +1889,16 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R } } +/* + * @brief Store F1-U UL TEID and address in RRC + */ +static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p) +{ + f1u->teid = p->teId; + memcpy(&f1u->addr.buffer, &p->tlAddress, sizeof(uint8_t) * 4); + f1u->addr.length = sizeof(in_addr_t); +} + /* \brief use list of DRBs and send the corresponding bearer update message via * E1 to the CU of this UE. Also updates TEID info internally */ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) @@ -2165,6 +2175,15 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp rrc_pdu->param.gNB_teid_N3 = e1_pdu->teId; memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tlAddress, sizeof(uint8_t) * 4); rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t); + + // save the tunnel address for the DRBs + for (int i = 0; i < e1_pdu->numDRBSetup; i++) { + DRB_nGRAN_setup_t *drb_config = &e1_pdu->DRBnGRanList[i]; + // numUpParam only relevant in F1, but not monolithic + AssertFatal(drb_config->numUpParam <= 1, "can only up to one UP param\n"); + drb_t *drb = get_drb(UE, drb_config->id); + f1u_ul_gtp_update(&drb->cuup_tunnel_config, &drb_config->UpParamList[0]); + } } /* Instruction towards the DU for DRB configuration and tunnel creation */ From fe9c0fba2fcef94619df13a36236ccd508aba588 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 18:23:32 +0200 Subject: [PATCH 23/33] Refactor DRB filling from E1 response in separate function Refactor this to allow the reuse of this function for handover later. --- openair2/RRC/NR/rrc_gNB.c | 108 ++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 4e5593e8b5..c7e21671bc 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2147,6 +2147,67 @@ static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, return NULL; } +/* \bref return F1AP QoS characteristics based on Qos flow parameters */ +static f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param) +{ + f1ap_qos_characteristics_t qos_char = {0}; + if (qos_param->fiveQI_type == dynamic) { + qos_char.qos_type = dynamic; + qos_char.dynamic.fiveqi = qos_param->fiveQI; + qos_char.dynamic.qos_priority_level = qos_param->qos_priority; + } else { + qos_char.qos_type = non_dynamic; + qos_char.non_dynamic.fiveqi = qos_param->fiveQI; + qos_char.non_dynamic.qos_priority_level = qos_param->qos_priority; + } + return qos_char; +} + +/* \brief fills a list of DRBs to be setup from a number of PDU sessions in E1 + * bearer setup response */ +static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + const pdu_session_setup_t *pduSession, + int numPduSession, + f1ap_drb_to_be_setup_t drbs[32]) +{ + int nb_drb = 0; + for (int p = 0; p < numPduSession; ++p) { + rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, pduSession[p].id, false); + DevAssert(RRC_pduSession); + for (int i = 0; i < pduSession[p].numDRBSetup; i++) { + const DRB_nGRAN_setup_t *drb_config = &pduSession[p].DRBnGRanList[i]; + f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; + drb->drb_id = pduSession[p].DRBnGRanList[i].id; + drb->rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; + drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; + drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; + drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; + drb->up_ul_tnl_length = 1; + + /* pass QoS info to MAC */ + int nb_qos_flows = drb_config->numQosFlowSetup; + AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n"); + drb->drb_info.flows_to_be_setup_length = nb_qos_flows; + drb->drb_info.flows_mapped_to_drb = calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t)); + AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); + for (int j = 0; j < nb_qos_flows; j++) { + drb->drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi; + pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession); + drb->drb_info.flows_mapped_to_drb[j].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; + + /* pass NSSAI info to MAC */ + drb->nssai = RRC_pduSession->param.nssai; + + nb_drb++; + } + } + return nb_drb; +} + /** * @brief E1AP Bearer Context Setup Response processing on CU-CP */ @@ -2188,52 +2249,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp /* Instruction towards the DU for DRB configuration and tunnel creation */ f1ap_drb_to_be_setup_t drbs[32]; // maximum DRB can be 32 - int nb_drb = 0; - for (int p = 0; p < resp->numPDUSessions; ++p) { - rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, resp->pduSession[p].id, false); - DevAssert(RRC_pduSession); - for (int i = 0; i < resp->pduSession[p].numDRBSetup; i++) { - DRB_nGRAN_setup_t *drb_config = &resp->pduSession[p].DRBnGRanList[i]; - f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; - drb->drb_id = resp->pduSession[p].DRBnGRanList[i].id; - drb->rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; - drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; - drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; - drb->up_ul_tnl_length = 1; - - drb->nssai = RRC_pduSession->param.nssai; - - /* pass QoS info to MAC */ - int nb_qos_flows = drb_config->numQosFlowSetup; - AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n"); - drb->drb_info.flows_to_be_setup_length = nb_qos_flows; - drb->drb_info.flows_mapped_to_drb = calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t)); - AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); - for (int j = 0; j < nb_qos_flows; j++) { - drb->drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi; - - pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession); - f1ap_qos_characteristics_t *qos_char = &drb->drb_info.flows_mapped_to_drb[j].qos_params.qos_characteristics; - if (in_qos_char->fiveQI_type == dynamic) { - qos_char->qos_type = dynamic; - qos_char->dynamic.fiveqi = in_qos_char->fiveQI; - qos_char->dynamic.qos_priority_level = in_qos_char->qos_priority; - } else { - qos_char->qos_type = non_dynamic; - qos_char->non_dynamic.fiveqi = in_qos_char->fiveQI; - qos_char->non_dynamic.qos_priority_level = in_qos_char->qos_priority; - } - } - /* 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; - - /* pass NSSAI info to MAC */ - drb->nssai = RRC_pduSession->param.nssai; - - nb_drb++; - } - } + int nb_drb = fill_drb_to_be_setup_from_e1_resp(rrc, UE, resp->pduSession, resp->numPDUSessions, drbs); if (!UE->f1_ue_context_active) rrc_gNB_generate_UeContextSetupRequest(rrc, ue_context_p, nb_drb, drbs); From 35f7225fb4132314b2f74fc7ac84b899344924b9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 24 Jul 2024 16:09:52 +0200 Subject: [PATCH 24/33] Correct cuup_notify_reestablishment() look up errors cuup_notify_reestablishment() used &ue_p->established_drbs[drb_id] to look up a bearer, which is wrong, because it should be drb_id - 1 as in the top of the loop. Also, it used the dedicated get_drb() function; harmonize to use only this function. --- openair2/RRC/NR/rrc_gNB.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c7e21671bc..b1ab58b2ff 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -806,7 +806,8 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) return; /* loop through active DRBs */ for (int drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) { - if (ue_p->established_drbs[drb_id - 1].status == DRB_INACTIVE) + drb_t *drb = get_drb(ue_p, drb_id); + if (drb->status == DRB_INACTIVE) continue; /* fetch an existing PDU session for this DRB */ rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue_p, drb_id); @@ -827,13 +828,11 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; drb_e1->id = drb_id; drb_e1->numDlUpParam = 1; - drb_t *drbs = &ue_p->established_drbs[drb_id]; - memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drbs->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb_e1->DlUpParamList[0].teId = drbs->du_tunnel_config.teid; + memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb_e1->DlUpParamList[0].teId = drb->du_tunnel_config.teid; /* PDCP configuration */ bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config; - drb_t *rrc_drb = get_drb(ue_p, drb_id); - set_bearer_context_pdcp_config(pdcp_config, rrc_drb, rrc->configuration.um_on_default_drb); + set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb); pdcp_config->pDCP_Reestablishment = true; /* increase DRB to modify counter */ pdu_e1->numDRB2Modify += 1; From 1a9df52cf3363a45f647c8e105134eb66277471a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 24 Jul 2024 16:12:41 +0200 Subject: [PATCH 25/33] Fixup get_drb(): can have up to 32 DRBs --- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 10f16cb030..ab2bf13071 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -51,7 +51,7 @@ rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) { - DevAssert(drb_id > 0 && drb_id < 32); + DevAssert(drb_id > 0 && drb_id <= 32); DevAssert(ue != NULL); return &ue->established_drbs[drb_id - 1]; From b3d04c1bbf09235be3e50761f916850b93bf7a42 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Aug 2024 15:58:45 +0200 Subject: [PATCH 26/33] RETURN_IF_INVALID_ASSOC_ID(): use assoc_id directly In some cases, we don't have the ue_data that is used until this commit. Make this macro more general by only requiring the assoc_id to check. --- openair2/RRC/NR/rrc_gNB.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b1ab58b2ff..6035d05a67 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -113,9 +113,9 @@ mui_t rrc_gNB_mui = 0; // the assoc_id might be 0 (if the DU goes offline). Below helper macro to // print an error and return from the function in that case -#define RETURN_IF_INVALID_ASSOC_ID(ue_data) \ +#define RETURN_IF_INVALID_ASSOC_ID(assoc_id) \ { \ - if (ue_data.du_assoc_id == 0) { \ + if (assoc_id == 0) { \ LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); \ return; \ } \ @@ -197,7 +197,7 @@ void nr_rrc_transfer_protected_rrc_message(const gNB_RRC_INST *rrc, { DevAssert(size > 0); f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_dl_rrc_message_t dl_rrc = {.gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, .srb_id = srb_id}; deliver_dl_rrc_message_data_t data = {.rrc = rrc, .dl_rrc = &dl_rrc, .assoc_id = ue_data.du_assoc_id}; nr_pdcp_data_req_srb(ue_p->rrc_ue_id, @@ -423,7 +423,7 @@ static void rrc_gNB_generate_RRCSetup(instance_t instance, LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buf, size, "[MSG] RRC Setup\n"); freeSRBlist(SRBs); f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_dl_rrc_message_t dl_rrc = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -453,7 +453,7 @@ static void rrc_gNB_generate_RRCReject(module_id_t module_id, rrc_gNB_ue_context LOG_I(NR_RRC, " [RAPROC] ue %04x Logical Channel DL-CCCH, Generating NR_RRCReject (bytes %d)\n", ue_p->rnti, size); f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_dl_rrc_message_t dl_rrc = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -899,7 +899,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context &security_parameters); /* F1AP DL RRC Message Transfer */ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); uint32_t old_gNB_DU_ue_id = old_rnti; f1ap_dl_rrc_message_t dl_rrc = {.gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -2655,7 +2655,7 @@ rrc_gNB_generate_RRCRelease( gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; const gNB_RRC_UE_t *UE = &ue_context_pP->ue_context; f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_ue_context_release_cmd_t ue_context_release_cmd = { .gNB_CU_ue_id = UE->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -2781,7 +2781,7 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc, /* the callback will fill the UE context setup request and forward it */ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_ue_context_setup_t ue_context_setup_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -2825,7 +2825,7 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, } f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_ue_context_modif_req_t ue_context_modif_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, From b01810a8580baec28736d5e7fd89ef6370713b16 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 08:20:07 +0200 Subject: [PATCH 27/33] Introduce an_release flag: only free UE in RRC+ack if requested by core The F1AP UE context release procedure can happen in at least two cases: 1. core requested a release of a UE 2. CU requests DU a release of a UE without a core release (e.g., handover) In case 1., the CU has to fully release the UE in the CU, then ack the NGAP message from the core, whilst in 2., nothing of that should happen after the DU acknowledges the F1AP UE context release cmd. --- openair2/RRC/NR/nr_rrc_defs.h | 2 ++ openair2/RRC/NR/rrc_gNB.c | 8 +++++++- openair2/RRC/NR/rrc_gNB_NGAP.c | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index de4bd5f5ec..cff7395934 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -289,6 +289,8 @@ typedef struct gNB_RRC_UE_s { uint32_t ue_reestablishment_counter; uint32_t ue_reconfiguration_counter; + bool an_release; // flag if core requested UE release + /* NGUEContextSetup might come with PDU sessions, but setup needs to be * delayed after security (and capability); PDU sessions are stored here */ int n_initial_pdu; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6035d05a67..d7a879d248 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2030,7 +2030,13 @@ static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p) return; } - rrc_remove_ue(RC.nrrrc[0], ue_context_p); + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + if (UE->an_release) { + /* only trigger release if it has been requested by core + * otherwise, it might be CU that requested release on a DU during normal + * operation (i.e, handover) */ + rrc_remove_ue(RC.nrrrc[0], ue_context_p); + } } static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, instance_t instance) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index a98853af28..1ef1f8c808 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1180,6 +1180,7 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_ } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + UE->an_release = true; #ifdef E2_AGENT signal_rrc_state_changed_to(UE, RC_SM_RRC_IDLE); #endif From 327baf2938ddabfe4540589d047789149746186f Mon Sep 17 00:00:00 2001 From: Roberto Magueta Date: Tue, 3 Sep 2024 10:51:39 +0200 Subject: [PATCH 28/33] Bugfix: an A3 configuration is for a specific PCI Co-authored-by: Luis Pereira --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 13f704b2c7..85b679bc62 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1262,7 +1262,7 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, if (!neighbourCell->isIntraFrequencyNeighbour) continue; - const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->nrcell_id); + const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->physicalCellId); if (!a3Event || is_default_a3_added) continue; From fde10b92037dcd463fad676956480caf171d1488 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 14:14:27 +0200 Subject: [PATCH 29/33] Use u64 for neighbour nr_cellid: is up to 38 bits --- openair2/GNB_APP/gnb_config.c | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 0dfe99e3cb..dea4ebc9c5 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1598,7 +1598,7 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc paramdef_t NeighbourCellParams[] = GNBNEIGHBOURCELLPARAMS_DESC; paramlist_def_t NeighbourCellParamList = {GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, NULL, 0}; config_getlist(config_get_if(), &NeighbourCellParamList, NeighbourCellParams, sizeofArray(NeighbourCellParams), neighbourpath); - LOG_D(GNB_APP, "HO LOG: For the Cell: %d 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; diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index cff7395934..60830719b5 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -367,7 +367,7 @@ typedef struct { } nr_neighbour_gnb_configuration_t; typedef struct neighbour_cell_configuration_s { - int nr_cell_id; + uint64_t nr_cell_id; seq_arr_t *neighbour_cells; } neighbour_cell_configuration_t; From d6d7064c0b6c58e1828952211c07826493e24545 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 10:49:17 +0200 Subject: [PATCH 30/33] A3 Event is for a PCI: Rename variable to make this clear --- ci-scripts/conf_files/neighbour-config.conf | 4 ++-- openair2/GNB_APP/gnb_config.c | 4 ++-- openair2/GNB_APP/gnb_paramdef.h | 6 +++--- openair2/RRC/NR/MESSAGES/asn1_msg.c | 13 ++++++------- openair2/RRC/NR/MESSAGES/asn1_msg.h | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 2 +- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/ci-scripts/conf_files/neighbour-config.conf b/ci-scripts/conf_files/neighbour-config.conf index 12b023de7a..875129365e 100644 --- a/ci-scripts/conf_files/neighbour-config.conf +++ b/ci-scripts/conf_files/neighbour-config.conf @@ -62,12 +62,12 @@ nr_measurement_configuration = { }; A3 = ({ - cell_id = -1; #Default + physCellId = -1; #Default offset = 10; hysteresis = 0; timeToTrigger = 1 }, { - cell_id = 2; + physCellId = 2; offset = 5; hysteresis = 1; timeToTrigger = 2 diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index dea4ebc9c5..ef69264ac9 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1696,12 +1696,12 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) 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->cell_id = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_CELL_ID_IDX].i64ptr; + a3_event->pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; 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->cell_id == -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)); diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index a5d8cc5b42..253d94b44a 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -324,12 +324,12 @@ typedef enum { #define MEASUREMENT_EVENTS_THRESHOLD "threshold" #define MEASUREMENT_EVENTS_PERIODICAL_BEAM_MEASUREMENT "includeBeamMeasurements" #define MEASUREMENT_EVENTS_PERIODICAL_NR_OF_RS_INDEXES "maxNrofRS_IndexesToReport" -#define MEASUREMENT_EVENTS_CELL_ID "cell_id" +#define MEASUREMENT_EVENTS_PCI_ID "physCellId" #define MEASUREMENT_EVENT_ENABLE "enable" // clang-format off #define MEASUREMENT_A3_GLOBALPARAMS_DESC \ { \ - {MEASUREMENT_EVENTS_CELL_ID, "neighbour cellId for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \ + {MEASUREMENT_EVENTS_PCI_ID, "neighbour PCI for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \ {MEASUREMENT_EVENTS_TIME_TO_TRIGGER, "a3 time to trigger", 0, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \ {MEASUREMENT_EVENTS_OFFSET, "a3 offset", 0, .i64ptr = NULL, .defint64val = 60, TYPE_INT64, 0}, \ {MEASUREMENT_EVENTS_HYSTERESIS, "a3 hysteresis", 0, .i64ptr = NULL, .defint64val = 0, TYPE_INT64, 0}, \ @@ -350,7 +350,7 @@ typedef enum { } // clang-format on -#define MEASUREMENT_EVENTS_CELL_ID_IDX 0 +#define MEASUREMENT_EVENTS_PCI_ID_IDX 0 #define MEASUREMENT_EVENTS_ENABLE_IDX 0 #define MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX 1 #define MEASUREMENT_EVENTS_A2_THRESHOLD_IDX 2 diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 85b679bc62..25baed610a 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1165,10 +1165,9 @@ static NR_ReportConfigToAddMod_t *prepare_a2_event_report(const nr_a2_event_t *a static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event) { NR_ReportConfigToAddMod_t *rc_A3 = calloc(1, sizeof(*rc_A3)); - rc_A3->reportConfigId = - a3_event->cell_id == -1 - ? 3 - : a3_event->cell_id + 4; // 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID starts from 4 + // 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID + // starts from 4 + rc_A3->reportConfigId = a3_event->pci == -1 ? 3 : a3_event->pci + 4; rc_A3->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR; NR_EventTriggerConfig_t *etrc_A3 = calloc(1, sizeof(*etrc_A3)); etrc_A3->eventId.present = NR_EventTriggerConfig__eventId_PR_eventA3; @@ -1194,7 +1193,7 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a return rc_A3; } -const nr_a3_event_t *get_a3_configuration(int nr_cellid) +const nr_a3_event_t *get_a3_configuration(int pci) { gNB_RRC_INST *rrc = RC.nrrrc[0]; nr_measurement_configuration_t *measurementConfiguration = &rrc->measurementConfiguration; @@ -1203,7 +1202,7 @@ const nr_a3_event_t *get_a3_configuration(int nr_cellid) for (uint8_t i = 0; i < measurementConfiguration->a3_event_list->size; i++) { nr_a3_event_t *a3_event = (nr_a3_event_t *)seq_arr_at(measurementConfiguration->a3_event_list, i); - if (a3_event->cell_id == nr_cellid) + if (a3_event->pci == pci) return a3_event; } @@ -1266,7 +1265,7 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, if (!a3Event || is_default_a3_added) continue; - if (a3Event->cell_id == -1) + if (a3Event->pci == -1) is_default_a3_added = true; NR_ReportConfigToAddMod_t *rc_A3 = prepare_a3_event_report(a3Event); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 0d8b4c547f..623573d24f 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -143,7 +143,7 @@ int do_RRCReestablishment(rrc_gNB_ue_context_t *const ue_context_pP, int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t rrc_TransactionIdentifier); -const nr_a3_event_t *get_a3_configuration(int nr_cellid); +const nr_a3_event_t *get_a3_configuration(int pci); NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, int band, int scs, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 60830719b5..b5b27a6f4d 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -342,7 +342,7 @@ typedef struct { } nr_a2_event_t; typedef struct { - int cell_id; + int pci; long a3_offset; long hysteresis; long timeToTrigger; From 3cfc10ddaabb143e20a7fddff63e31927a8cddf7 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 5 Sep 2024 09:12:04 +0200 Subject: [PATCH 31/33] Bugfix: an A3 configuration is for a specific PCI Co-authored-by: Luis Pereira --- 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 d7a879d248..f7992d9757 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1282,7 +1282,7 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, // neighbour. if (!neighbour_cell_du_context && neighbour) { // No F1 connection but static neighbour configuration is available - const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->nrcell_id); + const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->physicalCellId); // Additional check - This part can be modified according to additional cell specific Handover Margin if (a3_event_configuration && ((a3_event_configuration->a3_offset + a3_event_configuration->hysteresis) From 5d05078f4e77b47d448096830c6f6baf0b0f3fe4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 14:15:22 +0200 Subject: [PATCH 32/33] Validate neighbour config when DUs connect --- openair2/GNB_APP/gnb_config.c | 5 +++ openair2/RRC/NR/rrc_gNB_du.c | 72 +++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index ef69264ac9..0cbe75bbeb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1697,6 +1697,11 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) 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, + "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; diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 43b657d91e..97bbb685c9 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -40,12 +40,17 @@ int get_ssb_scs(const struct f1ap_served_cell_info_t *cell_info) return cell_info->mode == F1AP_MODE_TDD ? cell_info->tdd.tbw.scs : cell_info->fdd.dl_tbw.scs; } +static int ssb_arfcn_mtc(const NR_MeasurementTimingConfiguration_t *mtc) +{ + /* format has been verified when accepting MeasurementTimingConfiguration */ + NR_MeasTimingList_t *mtlist = mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; + return mtlist->list.array[0]->frequencyAndTiming->carrierFreq; +} + int get_ssb_arfcn(const struct nr_rrc_du_container_t *du) { DevAssert(du != NULL && du->mtc != NULL); - /* format has been verified when accepting MeasurementTimingConfiguration */ - NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; - return mtlist->list.array[0]->frequencyAndTiming->carrierFreq; + return ssb_arfcn_mtc(du->mtc); } static int du_compare(const nr_rrc_du_container_t *a, const nr_rrc_du_container_t *b) @@ -197,6 +202,58 @@ static void label_intra_frequency_neighbours(gNB_RRC_INST *rrc, for_each(cell_neighbour_list, (void *)&ssb_arfcn, is_intra_frequency_neighbour); } +static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_configuration, const f1ap_served_cell_info_t *cell, int ssb_arfcn) +{ + 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); + if (nc->nrcell_id != cell->nr_cellid) + continue; + // current cell is in the nc config, check that config matches + if (nc->physicalCellId != cell->nr_pci) { + LOG_W(NR_RRC, "Cell %ld in neighbour config: PCI mismatch (%d vs %d)\n", cell->nr_cellid, cell->nr_pci, nc->physicalCellId); + return false; + } + if (cell->tac && nc->tac != *cell->tac) { + LOG_W(NR_RRC, "Cell %ld in neighbour config: TAC mismatch (%d vs %d)\n", cell->nr_cellid, *cell->tac, nc->tac); + return false; + } + if (ssb_arfcn != nc->absoluteFrequencySSB) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: SSB ARFCN mismatch (%d vs %d)\n", + cell->nr_cellid, + ssb_arfcn, + nc->absoluteFrequencySSB); + return false; + } + if (get_ssb_scs(cell) != nc->subcarrierSpacing) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: SCS mismatch (%d vs %d)\n", + cell->nr_cellid, + get_ssb_scs(cell), + nc->subcarrierSpacing); + return false; + } + if (cell->plmn.mcc != nc->plmn.mcc || cell->plmn.mnc != nc->plmn.mnc + || cell->plmn.mnc_digit_length != nc->plmn.mnc_digit_length) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: PLMN mismatch (%03d.%0*d vs %03d.%0*d)\n", + cell->nr_cellid, + cell->plmn.mcc, + cell->plmn.mnc_digit_length, + cell->plmn.mnc, + nc->plmn.mcc, + nc->plmn.mnc_digit_length, + nc->plmn.mnc); + return false; + } + LOG_D(NR_RRC, "Cell %ld is neighbor of cell %ld\n", cell->nr_cellid, neighbour_config->nr_cell_id); + } + } + return true; +} + void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) { AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n"); @@ -264,6 +321,15 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) NR_MeasurementTimingConfiguration_t *mtc = extract_mtc(cell_info->measurement_timing_config, cell_info->measurement_timing_config_len); + if (rrc->neighbour_cell_configuration + && !valid_du_in_neighbour_configs(rrc->neighbour_cell_configuration, cell_info, ssb_arfcn_mtc(mtc))) { + LOG_E(NR_RRC, "problem with DU %ld in neighbor configuration, rejecting DU\n", req->gNB_DU_id); + f1ap_setup_failure_t fail = {.cause = F1AP_CauseMisc_unspecified}; + rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); + ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); + return; + } + const f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info; NR_MIB_t *mib = NULL; NR_SIB1_t *sib1 = NULL; From ab89324b1ec38439ed07b5f014ba1350e1f069b4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 14:15:39 +0200 Subject: [PATCH 33/33] Pretty-print PLMN in F1 Setup Request --- openair2/RRC/NR/rrc_gNB_du.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 97bbb685c9..e20121e8c2 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -276,10 +276,12 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) f1ap_served_cell_info_t *cell_info = &req->cell[0].info; if (!rrc_gNB_plmn_matches(rrc, cell_info)) { LOG_E(NR_RRC, - "PLMN mismatch: CU %d%d, DU %d%d\n", + "PLMN mismatch: CU %03d.%0*d, DU %03d%0*d\n", rrc->configuration.mcc[0], + rrc->configuration.mnc_digit_length[0], rrc->configuration.mnc[0], cell_info->plmn.mcc, + cell_info->plmn.mnc_digit_length, cell_info->plmn.mnc); f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_plmn_not_served_by_the_gNB_CU}; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);