From 9cfdf9bb018f6c5b357e468c63d51b966c40a867 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 31 Jan 2024 16:05:15 +0100 Subject: [PATCH 01/47] Remove custom trigger bearer add/release code, does not work --- common/utils/telnetsrv/telnetsrv_bearer.c | 10 +- openair2/RRC/NR/rrc_gNB.c | 143 ---------------------- 2 files changed, 6 insertions(+), 147 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_bearer.c b/common/utils/telnetsrv/telnetsrv_bearer.c index 7281ac3e6b..4d8dacd82f 100644 --- a/common/utils/telnetsrv/telnetsrv_bearer.c +++ b/common/utils/telnetsrv/telnetsrv_bearer.c @@ -56,7 +56,7 @@ int get_single_rnti(char *buf, int debug, telnet_printfunc_t prnt) return 0; } -void rrc_gNB_trigger_new_bearer(int rnti); +//void rrc_gNB_trigger_new_bearer(int rnti); int add_bearer(char *buf, int debug, telnet_printfunc_t prnt) { int rnti = -1; @@ -75,12 +75,13 @@ int add_bearer(char *buf, int debug, telnet_printfunc_t prnt) if (!rrcue) ERROR_MSG_RET("could not find UE with RNTI %04x\n", rnti); - rrc_gNB_trigger_new_bearer(rnti); + AssertFatal(false, "not implemented\n"); + //rrc_gNB_trigger_new_bearer(rnti); prnt("called rrc_gNB_trigger_new_bearer(%04x)\n", rnti); return 0; } -void rrc_gNB_trigger_release_bearer(int rnti); +//void rrc_gNB_trigger_release_bearer(int rnti); int release_bearer(char *buf, int debug, telnet_printfunc_t prnt) { int rnti = -1; @@ -99,7 +100,8 @@ int release_bearer(char *buf, int debug, telnet_printfunc_t prnt) if (!rrcue) ERROR_MSG_RET("could not find UE with RNTI %04x\n", rnti); - rrc_gNB_trigger_release_bearer(rnti); + AssertFatal(false, "not implemented\n"); + //rrc_gNB_trigger_release_bearer(rnti); prnt("called rrc_gNB_trigger_release_bearer(%04x)\n", rnti); return 0; } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7c3c200f15..951421d705 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2642,149 +2642,6 @@ rrc_gNB_generate_RRCRelease( /* UE will be freed after UE context release complete */ } -void rrc_gNB_trigger_new_bearer(int rnti) -{ - /* get RRC and UE */ - gNB_RRC_INST *rrc = RC.nrrrc[0]; - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti_any_du(rrc, rnti); - if (ue_context_p == NULL) { - LOG_E(RRC, "unknown UE RNTI %04x\n", rnti); - return; - } - gNB_RRC_UE_t *ue = &ue_context_p->ue_context; - - /* get the existing PDU sessoin */ - if (ue->nb_of_pdusessions < 1) { - LOG_E(RRC, "no PDU session set up yet, cannot create additional bearer\n"); - return; - } - - if (ue->established_drbs[0].status != DRB_INACTIVE - && ue->established_drbs[1].status != DRB_INACTIVE) { - LOG_E(RRC, "already have two established bearers, aborting\n"); - return; - } - - e1ap_bearer_setup_req_t bearer_req = {0}; - bearer_req.gNB_cu_cp_ue_id = ue->rrc_ue_id; - bearer_req.cipheringAlgorithm = ue->ciphering_algorithm; - memcpy(bearer_req.encryptionKey, ue->kgnb, sizeof(ue->kgnb)); - bearer_req.integrityProtectionAlgorithm = ue->integrity_algorithm; - memcpy(bearer_req.integrityProtectionKey, ue->kgnb, sizeof(ue->kgnb)); - bearer_req.ueDlAggMaxBitRate = 10000; /* probably does not matter */ - - pdu_session_to_setup_t *pdu = &bearer_req.pduSession[0]; - //bearer_req.numPDUSessions++; - bearer_req.numPDUSessions = 1; - //pdu->sessionId = session->pdusession_id; - //pdu->sst = msg->allowed_nssai[i].sST; - //pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; - - //pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; - //pdu->teId = session->gtp_teid; - pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding - DRB_nGRAN_to_setup_t *drb = &pdu->DRBnGRanList[0]; - int drb_id = 2; - drb->id = drb_id; - - drb->defaultDRB = E1AP_DefaultDRB_false; - drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap); - drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap); - - drb->pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_18; - drb->pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_18; - - drb->discardTimer = E1AP_DiscardTimer_infinity; - drb->reorderingTimer = E1AP_T_Reordering_ms0; - - drb->rLC_Mode = E1AP_RLC_Mode_rlc_am; - - drb->numCellGroups = 1; // assume one cell group associated with a DRB - - for (int k=0; k < drb->numCellGroups; k++) { - cell_group_t *cellGroup = drb->cellGroupList + k; - cellGroup->id = 0; // MCG - } - - int xid = rrc_gNB_get_next_transaction_identifier(0); - /* generate a new bearer, it will be put into internal RRC state and picked - * up later */ - generateDRB(ue, - drb_id, - &ue->pduSession[0], - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering); - - /* associate the new bearer to it */ - ue->xids[xid] = RRC_PDUSESSION_MODIFY; - ue->pduSession[0].xid = xid; // hack: fake xid for ongoing PDU session - LOG_W(RRC, "trigger new bearer %ld for UE %04x xid %d\n", drb->id, ue->rnti, xid); - sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue); - rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); -} - -void rrc_gNB_trigger_release_bearer(int rnti) -{ - /* get RRC and UE */ - gNB_RRC_INST *rrc = RC.nrrrc[0]; - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti_any_du(rrc, rnti); - if (ue_context_p == NULL) { - LOG_E(RRC, "unknown UE RNTI %04x\n", rnti); - return; - } - gNB_RRC_UE_t *ue = &ue_context_p->ue_context; - - if (ue->established_drbs[1].status == DRB_INACTIVE) { - LOG_E(RRC, "no second bearer, aborting\n"); - return; - } - - // don't use E1: bearer release is not implemented, call directly - // into PDCP/SDAP and then send corresponding message via F1 - - int drb_id = 2; - ue->established_drbs[1].status = DRB_INACTIVE; - ue->DRB_ReleaseList = calloc(1, sizeof(*ue->DRB_ReleaseList)); - AssertFatal(ue->DRB_ReleaseList != NULL, "out of memory\n"); - NR_DRB_Identity_t *asn1_drb = malloc(sizeof(*asn1_drb)); - AssertFatal(asn1_drb != NULL, "out of memory\n"); - int idx = 0; - NR_DRB_ToAddModList_t *drb_list = createDRBlist(ue, false); - while (idx < drb_list->list.count) { - const NR_DRB_ToAddMod_t *drbc = drb_list->list.array[idx]; - if (drbc->drb_Identity == drb_id) - break; - ++idx; - } - if (idx < drb_list->list.count) { - nr_pdcp_release_drb(rnti, drb_id); - asn_sequence_del(&drb_list->list, idx, 1); - } - *asn1_drb = drb_id; - asn1cSeqAdd(&ue->DRB_ReleaseList->list, asn1_drb); - - f1ap_drb_to_be_released_t drbs_to_be_released[1] = {{.rb_id = drb_id}}; - f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); - f1ap_ue_context_modif_req_t ue_context_modif_req = { - .gNB_CU_ue_id = ue->rrc_ue_id, - .gNB_DU_ue_id = ue_data.secondary_ue, - .plmn.mcc = rrc->configuration.mcc[0], - .plmn.mnc = rrc->configuration.mnc[0], - .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], - .nr_cellid = rrc->nr_cellid, - .servCellId = 0, /* TODO: correct value? */ - .srbs_to_be_setup_length = 0, - .srbs_to_be_setup = NULL, - .drbs_to_be_setup_length = 0, - .drbs_to_be_setup = NULL, - .drbs_to_be_released_length = 1, - .drbs_to_be_released = drbs_to_be_released, - }; - rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); -} - int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint32_t tmsi, uint8_t paging_drx) { instance_t instance = 0; From 0a7e48f138cc985acd93101f586f27656f67c571 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 17:39:40 +0100 Subject: [PATCH 02/47] Remove a non-error in RU --- executables/nr-ru.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 8924c5729a..c61088dc88 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1812,10 +1812,6 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) LOG_E(PHY,"%s() DJP - ru->gNB_list ru->num_gNB are not initialized - so do it manually\n", __FUNCTION__); ru->gNB_list[0] = RC.gNB[0]; ru->num_gNB=1; - // - // - } else { - LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); } } From b09526c83e4c9787c363dc79ce5d84cf1678853b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Oct 2023 07:28:04 +0200 Subject: [PATCH 03/47] Bugfix: fix use-after-free of UE caps --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 3 --- 1 file changed, 3 deletions(-) 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 c764ece582..2c3a718fff 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -338,9 +338,6 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) UE->capability = ue_cap; if (ue_cap != NULL) { // store the new UE capabilities, and update the cellGroupConfig - ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->capability); - UE->capability = ue_cap; - LOG_I(NR_MAC, "UE %04x: received capabilities, updating CellGroupConfig\n", UE->rnti); NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc); } From a2c7f0c0b359d3c5a4e66a241e54b4c41895ca76 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2024 10:23:58 +0100 Subject: [PATCH 04/47] Remove possible NG Initial Context Setup Resp in handler for request 38.401 Sec 8.1 asks for sending the Initial Context Setup Response after a reconfiguration happened. Therefore, we can never send this message directly from the handler in the Initial Context Setup Request --- openair2/RRC/NR/rrc_gNB_NGAP.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 05067fe12f..972148947c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -429,12 +429,6 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p); - // in case, send the S1SP initial context response if it is not sent with the attach complete message - if (UE->StatusRrc == NR_RRC_RECONFIGURED) { - LOG_I(NR_RRC, "Sending rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP, cause %ld\n", UE->reestablishment_cause); - rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(&ctxt, ue_context_p); - } - return 0; } From 940d582568a98bafc92660c1a131e0bc27d5b4bc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 2 Jan 2024 12:18:35 +0100 Subject: [PATCH 05/47] Remove write-only gNB's UE reestablishment cause --- openair2/RRC/NR/nr_rrc_defs.h | 3 --- openair2/RRC/NR/rrc_gNB.c | 1 - 2 files changed, 4 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 17be416c12..d0acf96066 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -278,9 +278,6 @@ typedef struct gNB_RRC_UE_s { uint16_t ng_5G_S_TMSI_Part2; NR_EstablishmentCause_t establishment_cause; - /* Information from UE RRCReestablishmentRequest */ - NR_ReestablishmentCause_t reestablishment_cause; - uint32_t rrc_ue_id; uint64_t amf_ue_ngap_id; nr_rrc_guami_t ue_guami; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 951421d705..9208708ab1 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1338,7 +1338,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t f1_ue_data_t ue_data = {.secondary_ue = msg->gNB_DU_ue_id, .du_assoc_id = assoc_id}; cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data); - UE->reestablishment_cause = cause; LOG_D(NR_RRC, "Accept req-> UE physCellId %ld cause %ld\n", physCellId, cause); rrc_gNB_generate_RRCReestablishment(ue_context_p, msg->du2cu_rrc_container, old_rnti, du); From 4b81e9a481aad2048bebd3301601a1a23ddcc018 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Oct 2023 07:33:41 +0200 Subject: [PATCH 06/47] Introduce UE flag for AS security Keeping track if AS security is activated. This is important for a later commit, where we use this to decide if we send a F1 UE Context Setup Req with security command after receiving the E1 bearer context setup response. The corresponding AssertFatal() removed in the same commit implementing PDU session handling in NGAP Initial UE Context Setup. --- openair2/RRC/NR/nr_rrc_defs.h | 2 ++ openair2/RRC/NR/rrc_gNB.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index d0acf96066..b0702a2f0d 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -245,6 +245,8 @@ typedef struct gNB_RRC_UE_s { NR_HANDOVER_INFO *handover_info; NR_MeasResults_t *measResults; + bool as_security_active; + byte_array_t ue_cap_buffer; NR_UE_NR_Capability_t* UE_Capability_nr; int UE_Capability_size; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 9208708ab1..e473772bff 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1330,6 +1330,15 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t return; } + 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"); + ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); + ue_context_p->ue_context.Srb[1].Active = 1; + rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + return; + } + /* TODO: start timer in ITTI and drop UE if it does not come back */ // update with new RNTI, and update secondary UE association @@ -1734,6 +1743,7 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, /* configure ciphering */ nr_rrc_pdcp_config_security(ctxt_pP, ue_context_p, 1); + ue_context_p->ue_context.as_security_active = true; rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); break; @@ -2146,6 +2156,13 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp srbs[0].lcid = 2; } + if (!UE->as_security_active) { + /* no AS security active, need to send UE context setup req with security + * command (and the bearers) */ + AssertFatal(false, "not implemented yet\n"); + return; + } + /* Gather UE capability if present */ cu_to_du_rrc_information_t cu2du = {0}; cu_to_du_rrc_information_t *cu2du_p = NULL; @@ -2519,6 +2536,7 @@ rrc_gNB_generate_SecurityModeCommand( uint8_t buffer[100]; uint8_t size; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; + AssertFatal(!ue_p->as_security_active, "logic error: security already active\n"); T(T_ENB_RRC_SECURITY_MODE_COMMAND, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rntiMaybeUEid)); NR_IntegrityProtAlgorithm_t integrity_algorithm = (NR_IntegrityProtAlgorithm_t)ue_p->integrity_algorithm; From f6a783344fde57dd0476cf94696aa17f14ee38f2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 9 Jan 2024 17:35:56 +0100 Subject: [PATCH 07/47] Handle reestablishment from different PCI, simplified implementation This implementation might work, but it simply triggers RRC setup on the new DU when we might send a RRC reestablishment speeding up the whole connection setup. For this: - we should send the F1 UE context setup to the new DU - we should still do the reestablishment, containing the reestablishment message The latter should be sent once we received the F1 UE context setup response. We don't need a new context. send a release to the old DU (and don't release our own context!!). We might also send the reestablishment to the UE encapsulated with the F1 UE context setup response. Need to investigate if this is feasible (because if the DU rejects [can that happen here?], the UE will still send reestablishment complete -- what then?). Also, we would need to send the E1 bearer context modification to the CU-UP. --- openair2/RRC/NR/rrc_gNB.c | 40 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e473772bff..a511658c2d 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1263,6 +1263,11 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, const NR_RRCReestablishmentRequest_IEs_t *req, const f1ap_initial_ul_rrc_message_t *msg) { + /* in case we need to do RRC Setup, give the UE a new random identity */ + uint64_t random_value; + fill_random(&random_value, sizeof(random_value)); + random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ + const NR_ReestablishmentCause_t cause = req->reestablishmentCause; const long physCellId = req->ue_Identity.physCellId; LOG_I(NR_RRC, @@ -1278,25 +1283,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t LOG_E(RRC, "received CCCH message, but no corresponding DU found\n"); return; } - const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; - if (physCellId != cell_info->nr_pci) { - /* UE was moving from previous cell so quickly that RRCReestablishment for previous cell was received in this cell */ - LOG_E(NR_RRC, - " NR_RRCReestablishmentRequest ue_Identity.physCellId(%ld) is not equal to current physCellId(%d), fallback to RRC " - "establishment\n", - physCellId, - cell_info->nr_pci); - /* 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" we did not implement this yet; TBD for Multi-DU */ - AssertFatal(false, "not implemented\n"); - return; - } - /* in case we need to do RRC Setup, give the UE a new random identity */ - uint64_t random_value; - fill_random(&random_value, sizeof(random_value)); - random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ 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 @@ -1317,6 +1304,23 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t return; } + const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; + if (physCellId != cell_info->nr_pci) { + /* UE was moving from previous cell so quickly that RRCReestablishment for previous cell was received in this cell */ + LOG_I(NR_RRC, + "RRC Reestablishment Request from different physCellId (%ld) than current physCellId (%d), fallback to RRC setup\n", + physCellId, + cell_info->nr_pci); + /* 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 + * ongoing context at the CU. Hence, create new below */ + rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); + new->ue_context.Srb[1].Active = 1; + rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + return; + } + 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) { From 674d9bcd8a8bba04c9d999c0a9bc72b65eb8a4e8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2024 09:21:24 +0100 Subject: [PATCH 08/47] rrc_handle_RRCReestablishmentRequest(): refactor to have single block for RRC Setup --- openair2/RRC/NR/rrc_gNB.c | 67 ++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a511658c2d..0523b68ffb 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1261,22 +1261,27 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); } +static const char *get_reestab_cause(NR_ReestablishmentCause_t c) +{ + switch (c) { + case NR_ReestablishmentCause_otherFailure: + return "Other Failure"; + case NR_ReestablishmentCause_handoverFailure: + return "Handover Failure"; + case NR_ReestablishmentCause_reconfigurationFailure: + return "Reconfiguration Failure"; + default: + break; + } + return "UNKNOWN Failure (ASN.1 decoder error?)"; +} + static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, const NR_RRCReestablishmentRequest_IEs_t *req, const f1ap_initial_ul_rrc_message_t *msg) { - /* in case we need to do RRC Setup, give the UE a new random identity */ - uint64_t random_value; - fill_random(&random_value, sizeof(random_value)); - random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ - - const NR_ReestablishmentCause_t cause = req->reestablishmentCause; + uint64_t random_value = 0; + const char *scause = get_reestab_cause(req->reestablishmentCause); const long physCellId = req->ue_Identity.physCellId; - LOG_I(NR_RRC, - "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", - msg->crnti, - physCellId, - cause == NR_ReestablishmentCause_otherFailure - ? "Other Failure" - : (cause == NR_ReestablishmentCause_handoverFailure ? "Handover Failure" : "reconfigurationFailure")); + LOG_D(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) { @@ -1289,19 +1294,14 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t * Reestablishment (as we would need the SSB's ARFCN, which we cannot * compute). So generate RRC Setup instead */ LOG_E(NR_RRC, "Reestablishment request: no MIB/SIB1 of DU present, cannot do reestablishment, force setup request\n"); - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - ue_context_p->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + goto fallback_rrc_setup; } 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); if (ue_context_p == NULL) { LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); - ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - ue_context_p->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); - return; + goto fallback_rrc_setup; } const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; @@ -1315,10 +1315,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t * 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 * ongoing context at the CU. Hence, create new below */ - rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - new->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); - return; + goto fallback_rrc_setup; } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; @@ -1328,19 +1325,13 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t LOG_E(NR_RRC, "NR_RRCReestablishmentRequest c_RNTI %04lx range error, fallback to RRC setup\n", req->ue_Identity.c_RNTI); - ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - ue_context_p->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); - return; + 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"); - ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - ue_context_p->ue_context.Srb[1].Active = 1; - rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); - return; + goto fallback_rrc_setup; } /* TODO: start timer in ITTI and drop UE if it does not come back */ @@ -1351,9 +1342,19 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t f1_ue_data_t ue_data = {.secondary_ue = msg->gNB_DU_ue_id, .du_assoc_id = assoc_id}; cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data); - LOG_D(NR_RRC, "Accept req-> UE physCellId %ld cause %ld\n", physCellId, cause); + 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; + +fallback_rrc_setup: + fill_random(&random_value, sizeof(random_value)); + random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ + + rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); + new->ue_context.Srb[1].Active = 1; + rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + return; } /*! \fn uint64_t bitStr_to_uint64(BIT_STRING_t *) From 8ec4279613e6060cd543e1a219533acfaa2d4503 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 16:32:24 +0100 Subject: [PATCH 09/47] Release SDAP when releasing UE over E1 --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 1 + openair2/SDAP/nr_sdap/nr_sdap_entity.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index e90a5a4309..231db3f548 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -278,6 +278,7 @@ void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) if (f1inst >= 0) // is there F1-U? newGtpuDeleteAllTunnels(f1inst, cmd->gNB_cu_up_ue_id); nr_pdcp_remove_UE(cmd->gNB_cu_up_ue_id); + nr_sdap_delete_ue_entities(cmd->gNB_cu_up_ue_id); if (need_ue_id_mgmt) { cu_remove_f1_ue_data(cmd->gNB_cu_up_ue_id); } diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index d7a4e74fc1..e119b2407a 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -556,7 +556,7 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id) entityPrev->next_entity = entityPtr->next_entity; free(entityPtr); entityPtr = entityPrev->next_entity; - LOG_D(SDAP, "Successfully deleted Entity.\n"); + LOG_I(SDAP, "Successfully deleted SDAP entity for UE %ld\n", ue_id); ret = true; } } From 4ed6c581ec0374808ced07bb9655d6d9353b456d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 14:45:34 +0100 Subject: [PATCH 10/47] gNB RRC: remove SA checks If we are in one of these procedures, we basically must be in SA mode, everything else is illogical. It also does not seem plausible to check for this, as it is not apparent why only these couple of calls should not be executed if not in SA. Hence, remove. --- openair2/RRC/NR/rrc_gNB.c | 74 ++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 0523b68ffb..20ee208f89 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -530,11 +530,7 @@ static void rrc_gNB_process_RRCSetupComplete(const protocol_ctxt_t *const ctxt_p 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"); - if (get_softmodem_params()->sa) { - rrc_gNB_send_NGAP_NAS_FIRST_REQ(ctxt_pP, ue_context_pP, rrcSetupComplete); - } else { - rrc_gNB_generate_SecurityModeCommand(ctxt_pP, ue_context_pP); - } + rrc_gNB_send_NGAP_NAS_FIRST_REQ(ctxt_pP, ue_context_pP, rrcSetupComplete); } //----------------------------------------------------------------------------- @@ -1102,11 +1098,9 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co ue_p->StatusRrc = NR_RRC_CONNECTED; ue_p->Srb[1].Active = 1; - if (get_softmodem_params()->sa) { - uint8_t send_security_mode_command = false; - nr_rrc_pdcp_config_security(ctxt_pP, ue_context_pP, send_security_mode_command); - LOG_D(NR_RRC, "RRC Reestablishment - set security successfully \n"); - } + + uint8_t send_security_mode_command = false; + nr_rrc_pdcp_config_security(ctxt_pP, ue_context_pP, send_security_mode_command); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; NR_CellGroupConfig_t *cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t)); @@ -1515,9 +1509,7 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, return -1; } - if (get_softmodem_params()->sa) { - rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, ue_cap_info); - } + rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, ue_cap_info); // we send the UE capabilities request before RRC connection is complete, // so we cannot have a PDU session yet @@ -1598,33 +1590,31 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ rrc_gNB_process_RRCReconfigurationComplete(ctxt_pP, ue_context_p, xid); bool successful_reconfig = true; - if (get_softmodem_params()->sa) { - switch (UE->xids[xid]) { - case RRC_PDUSESSION_RELEASE: { - gtpv1u_gnb_delete_tunnel_req_t req = {0}; - gtpv1u_delete_ngu_tunnel(ctxt_pP->instance, &req); - // NGAP_PDUSESSION_RELEASE_RESPONSE - rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(ctxt_pP, ue_context_p, xid); - } break; - case RRC_PDUSESSION_ESTABLISH: - if (UE->nb_of_pdusessions > 0) - rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(ctxt_pP, ue_context_p, xid); - break; - case RRC_PDUSESSION_MODIFY: - rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(ctxt_pP, ue_context_p, xid); - break; - case RRC_DEFAULT_RECONF: - rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP, ue_context_p); - break; - case RRC_REESTABLISH_COMPLETE: - case RRC_DEDICATED_RECONF: - /* do nothing */ - break; - default: - LOG_E(RRC, "Received unexpected transaction type %d for xid %d\n", UE->xids[xid], xid); - successful_reconfig = false; - break; - } + switch (UE->xids[xid]) { + case RRC_PDUSESSION_RELEASE: { + gtpv1u_gnb_delete_tunnel_req_t req = {0}; + gtpv1u_delete_ngu_tunnel(ctxt_pP->instance, &req); + // NGAP_PDUSESSION_RELEASE_RESPONSE + rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(ctxt_pP, ue_context_p, xid); + } break; + case RRC_PDUSESSION_ESTABLISH: + if (UE->nb_of_pdusessions > 0) + rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(ctxt_pP, ue_context_p, xid); + break; + case RRC_PDUSESSION_MODIFY: + rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(ctxt_pP, ue_context_p, xid); + break; + case RRC_DEFAULT_RECONF: + rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP, ue_context_p); + break; + case RRC_REESTABLISH_COMPLETE: + case RRC_DEDICATED_RECONF: + /* do nothing */ + break; + default: + LOG_E(RRC, "Received unexpected transaction type %d for xid %d\n", UE->xids[xid], xid); + successful_reconfig = false; + break; } gNB_RRC_INST *rrc = RC.nrrrc[0]; @@ -1718,9 +1708,7 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, LOG_D(NR_RRC, "[MSG] RRC UL Information Transfer \n"); LOG_DUMPMSG(RRC, DEBUG_RRC, (char *)Rx_sdu, sdu_sizeP, "[MSG] RRC UL Information Transfer \n"); - if (get_softmodem_params()->sa) { - rrc_gNB_send_NGAP_UPLINK_NAS(ctxt_pP, ue_context_p, ul_dcch_msg); - } + rrc_gNB_send_NGAP_UPLINK_NAS(ctxt_pP, ue_context_p, ul_dcch_msg); break; case NR_UL_DCCH_MessageType__c1_PR_securityModeComplete: From 13a4a20495270d8518b58445c4b5f6614b285256 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 17:15:18 +0100 Subject: [PATCH 11/47] Improve gNB MAC logs - Demote logs judged unimportant to debug - Indicate UE for UL failure - set_QoSConfig(): correct log --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 8 ++++---- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 8 +++++--- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index b901810c2e..c521a517e0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1698,7 +1698,7 @@ static void nr_generate_Msg4(module_id_t module_idP, // Need to wait until data for Msg4 is ready if (srb_status.bytes_in_buffer == 0) return; - LOG_I(NR_MAC, "(%4d.%2d) SRB%d has %d bytes\n", frameP, slotP, lcid, srb_status.bytes_in_buffer); + LOG_D(NR_MAC, "(%4d.%2d) SRB%d has %d bytes\n", frameP, slotP, lcid, srb_status.bytes_in_buffer); mac_sdu_length = srb_status.bytes_in_buffer; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 04162b8f37..4daf838cb3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2851,11 +2851,11 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot) { - LOG_I(NR_MAC, "%4d.%2d RNTI %04x: RRC processing timer expired\n", frame, slot, UE->rnti); + LOG_D(NR_MAC, "%4d.%2d RNTI %04x: RRC processing timer expired\n", frame, slot, UE->rnti); /* check if there is a new CellGroupConfig to be applied */ if (UE->apply_cellgroup && UE->reconfigCellGroup != NULL) { - LOG_I(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after RRC processing timer expiry\n", frame, slot, UE->rnti); + LOG_D(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after RRC processing timer expiry\n", frame, slot, UE->rnti); ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = UE->reconfigCellGroup; UE->reconfigCellGroup = NULL; @@ -2911,7 +2911,7 @@ int nr_mac_enable_ue_rrc_processing_timer(gNB_MAC_INST *mac, NR_UE_info_t *UE, b // frames, after RRC processing timer. UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024; - LOG_I(NR_MAC, "%4d.%2d UE %04x: Activate RRC processing timer (%d ms)\n", mac->frame, mac->slot, UE->rnti, delay); + LOG_D(NR_MAC, "%4d.%2d UE %04x: Activate RRC processing timer (%d ms)\n", mac->frame, mac->slot, UE->rnti, delay); return 0; } @@ -3092,7 +3092,7 @@ void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ct /* to trigger only once: trigger when ul_failure_timer == 1, but timer will * stop at 0 and we wait for a UE release command from upper layers */ if (sched_ctrl->ul_failure_timer == 1) { - LOG_W(MAC, "request release after UL failure timer expiry\n"); + LOG_W(MAC, "UE %04x: request release after UL failure timer expiry\n", rnti); f1_ue_data_t ue_data = du_get_f1_ue_data(rnti); f1ap_ue_context_release_req_t request = { .gNB_CU_ue_id = ue_data.secondary_ue, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index f1a3e34c85..1d9630cf00 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -676,9 +676,11 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, } if (!get_softmodem_params()->phy_test && UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt >= pusch_failure_thres) { - LOG_W(NR_MAC,"Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", - UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt); - nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); + LOG_W(NR_MAC, + "UE %04x: Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", + UE->rnti, + UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt); + nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); } } } else if(sduP) { 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 2c3a718fff..13aa2a3546 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -260,7 +260,7 @@ static void set_QoSConfig(const f1ap_ue_context_modif_req_t *req, NR_UE_sched_ct f1ap_drb_to_be_setup_t *drb_p = &req->drbs_to_be_setup[i]; uint8_t nb_qos_flows = drb_p->drb_info.flows_to_be_setup_length; long drb_id = drb_p->drb_id; - LOG_I(NR_MAC, "In %s: number of QOS flows mapped to DRB_id %d: %ld \n", __func__, drb_count, drb_id); + LOG_I(NR_MAC, "number of QOS flows mapped to DRB_id %ld: %d\n", drb_id, nb_qos_flows); for (int q = 0; q < nb_qos_flows; q++) { f1ap_flows_mapped_to_drb_t *qos_flow = &drb_p->drb_info.flows_mapped_to_drb[q]; From 9a417ca61cd177efb9298d791d94faaff52e9213 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 17:15:26 +0100 Subject: [PATCH 12/47] Demote RRC log to debug --- 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 20ee208f89..6b37803bc5 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -273,7 +273,7 @@ static int get_ssb_arfcn(const f1ap_served_cell_info_t *cell_info, const NR_MIB_ int band_size_hz = get_supported_bw_mhz(band > 256 ? FR2 : FR1, bw_index) * 1000 * 1000; uint32_t ssb_arfcn = to_nrarfcn(band, freqssb, scs, band_size_hz); - LOG_W(RRC, "freqpointa %ld Hz/%d offsetToPointA %ld kssb %ld scs %d band %d band_size_hz %d freqssb %ld Hz/%d\n", freqpointa, dl_arfcn, offsetToPointA, kssb, scs, band, band_size_hz, freqssb, ssb_arfcn); + LOG_D(RRC, "freqpointa %ld Hz/%d offsetToPointA %ld kssb %ld scs %d band %d band_size_hz %d freqssb %ld Hz/%d\n", freqpointa, dl_arfcn, offsetToPointA, kssb, scs, band, band_size_hz, freqssb, ssb_arfcn); if (RC.nrmac) { // debugging: let's test this is the correct ARFCN From da7c02b872c30dc720cff2f9ef2c85e38adaad8f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 18:23:43 +0100 Subject: [PATCH 13/47] PDCP: add log to info for adding/releasing bearer --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index c86bb686c4..73e015976d 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -925,7 +925,7 @@ void add_drb(int is_gnb, has_integrity ? integrity_key : NULL); nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb); - LOG_D(PDCP, "added drb %d to UE ID %ld\n", drb_id, UEid); + LOG_I(PDCP, "added drb %d to UE ID %ld\n", drb_id, UEid); new_nr_sdap_entity(is_gnb, has_sdap_rx, has_sdap_tx, UEid, pdusession_id, is_sdap_DefaultDRB, drb_id, mappedQFIs2Add, mappedQFIs2AddCount); } @@ -1193,6 +1193,7 @@ void nr_pdcp_release_drb(ue_id_t ue_id, int drb_id) drb->release_entity(drb); drb->delete_entity(drb); ue->drb[drb_id - 1] = NULL; + LOG_I(PDCP, "release DRB %d of UE %ld\n", drb_id, ue_id); } else LOG_E(PDCP, "Attempting to release DRB%d but it is not configured\n", drb_id); From 18d16db31159d855d94f56ad63f172ea0169ae48 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 9 Jan 2024 17:37:07 +0100 Subject: [PATCH 14/47] Demote NGAP error to warning, as it is not an error --- openair3/NGAP/ngap_gNB_handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 0fb9fd0dbc..fb9952e35c 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -732,7 +732,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), &(msg->ue_ambr.br_dl)); } else { - NGAP_ERROR("could not found NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate\n"); + NGAP_WARN("could not find NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate\n"); } From a205ba7eb0eb4c2be4781769ce274b5e8af2b632 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 1 Feb 2024 16:55:38 +0100 Subject: [PATCH 15/47] Complete NGAP PDU session logs with addr/TEIDs --- openair3/NGAP/ngap_gNB_nas_procedures.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 6d67920bcb..21144e4beb 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -631,7 +631,14 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].gtp_teid, &tmp->gTP_TEID); allocAddrCopy(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); - NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld\n", item->pDUSessionID); + NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", + item->pDUSessionID, + tmp->transportLayerAddress.buf[0], + tmp->transportLayerAddress.buf[1], + tmp->transportLayerAddress.buf[2], + tmp->transportLayerAddress.buf[3], + tmp->transportLayerAddress.size, + initial_ctxt_resp_p->pdusessions[i].gtp_teid); /* associatedQosFlowList. number of 1? */ for(int j=0; j < initial_ctxt_resp_p->pdusessions[i].nb_of_qos_flow; j++) { @@ -885,13 +892,14 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID); allocAddrCopy(&tmp->transportLayerAddress, pdusession->gNB_addr); - NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld \n", + NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, tmp->transportLayerAddress.buf[0], tmp->transportLayerAddress.buf[1], tmp->transportLayerAddress.buf[2], tmp->transportLayerAddress.buf[3], - tmp->transportLayerAddress.size); + tmp->transportLayerAddress.size, + pdusession->gtp_teid); /* associatedQosFlowList. number of 1? */ for(int j=0; j < pdusession_setup_resp_p->pdusessions[i].nb_of_qos_flow; j++) { asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); From 52bfd463de3c85868541239eb43c409801bcdbfe Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 17:37:20 +0100 Subject: [PATCH 16/47] Demote multiple non-error logs to warning in RFsim In all these cases, we simply continue with processing; it therefore seems that these are more warnings than errors. --- radio/rfsimulator/simulator.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 5dea88edd5..44b2864f8c 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -735,10 +735,10 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp } if ( t->lastWroteTS != 0 && fabs((double)t->lastWroteTS-timestamp) > (double)CirSize) - LOG_E(HW, "Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp); + LOG_W(HW, "Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp); if (t->lastWroteTS > timestamp+nsamps) - LOG_E(HW, "Not supported to send Tx out of order (same in USRP) %lu, %lu\n", t->lastWroteTS, timestamp); + LOG_W(HW, "Not supported to send Tx out of order %lu, %lu\n", t->lastWroteTS, timestamp); t->lastWroteTS=timestamp+nsamps; @@ -872,14 +872,14 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi } else if (b->lastReceivedTS == b->th.timestamp) { // normal case } else { - LOG_E(HW, "Received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); + LOG_W(HW, "Received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); b->trashingPacket=true; } pthread_mutex_lock(&Sockmutex); if (t->lastWroteTS != 0 && (fabs((double)t->lastWroteTS-b->lastReceivedTS) > (double)CirSize)) - LOG_E(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, t->lastWroteTS, b->lastReceivedTS); + LOG_W(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, t->lastWroteTS, b->lastReceivedTS); pthread_mutex_unlock(&Sockmutex); b->transferPtr=(char *)&b->circularBuf[(b->lastReceivedTS*b->th.nbAnt)%CirSize]; From ba5c34c1f6ae63c31b6bd5d74450fe1d344b1ec1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 16:02:07 +0100 Subject: [PATCH 17/47] oai_asn1.h: const-correctness/signal input parameter --- common/utils/oai_asn1.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/utils/oai_asn1.h b/common/utils/oai_asn1.h index 60a5b39ac5..f55150d17f 100644 --- a/common/utils/oai_asn1.h +++ b/common/utils/oai_asn1.h @@ -32,7 +32,7 @@ *\param[in] pointer to the BIT_STRING_t object. *\return the extracted value. */ -static inline uint8_t BIT_STRING_to_uint8(BIT_STRING_t *asn) { +static inline uint8_t BIT_STRING_to_uint8(const BIT_STRING_t *asn) { DevCheck ((asn->size == 1), asn->size, 0, 0); return asn->buf[0] >> asn->bits_unused; @@ -43,7 +43,7 @@ static inline uint8_t BIT_STRING_to_uint8(BIT_STRING_t *asn) { *\param[in] pointer to the BIT_STRING_t object. *\return the extracted value. */ -static inline uint16_t BIT_STRING_to_uint16(BIT_STRING_t *asn) { +static inline uint16_t BIT_STRING_to_uint16(const BIT_STRING_t *asn) { uint16_t result = 0; int index = 0; @@ -69,7 +69,7 @@ static inline uint16_t BIT_STRING_to_uint16(BIT_STRING_t *asn) { *\param[in] pointer to the BIT_STRING_t object. *\return the extracted value. */ -static inline uint32_t BIT_STRING_to_uint32(BIT_STRING_t *asn) { +static inline uint32_t BIT_STRING_to_uint32(const BIT_STRING_t *asn) { uint32_t result = 0; size_t index; @@ -91,7 +91,7 @@ static inline uint32_t BIT_STRING_to_uint32(BIT_STRING_t *asn) { *\param[in] pointer to the BIT_STRING_t object. *\return the extracted value. */ -static inline uint64_t BIT_STRING_to_uint64(BIT_STRING_t *asn) { +static inline uint64_t BIT_STRING_to_uint64(const BIT_STRING_t *asn) { uint64_t result = 0; size_t index; int shift; From d536c115d2552a959fab38a8ee0c81266c0455b2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 16:19:18 +0100 Subject: [PATCH 18/47] Replace custom bitStr_to_uint64() with common implementation --- openair2/RRC/NR/rrc_gNB.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6b37803bc5..0e3f534573 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -106,8 +106,6 @@ extern RAN_CONTEXT_t RC; -static inline uint64_t bitStr_to_uint64(const BIT_STRING_t *asn); - mui_t rrc_gNB_mui = 0; // the assoc_id might be 0 (if the DU goes offline). Below helper macro to @@ -1214,7 +1212,7 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, return; } - uint64_t s_tmsi_part1 = bitStr_to_uint64(&rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1); + uint64_t s_tmsi_part1 = BIT_STRING_to_uint64(&rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1); // memcpy(((uint8_t *) & random_value) + 3, // rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1.buf, @@ -1351,29 +1349,6 @@ fallback_rrc_setup: return; } -/*! \fn uint64_t bitStr_to_uint64(BIT_STRING_t *) - *\brief This function extract at most a 64 bits value from a BIT_STRING_t object, the exact bits number depend on the BIT_STRING_t contents. - *\param[in] pointer to the BIT_STRING_t object. - *\return the extracted value. - */ -static inline uint64_t bitStr_to_uint64(const BIT_STRING_t *asn) { - uint64_t result = 0; - int index; - int shift; - - DevCheck ((asn->size > 0) && (asn->size <= 8), asn->size, 0, 0); - - shift = ((asn->size - 1) * 8) - asn->bits_unused; - for (index = 0; index < (asn->size - 1); index++) { - result |= (uint64_t)asn->buf[index] << shift; - shift -= 8; - } - - result |= asn->buf[index] >> asn->bits_unused; - - return result; -} - static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context, NR_MeasurementReport_t *measurementReport) { if (LOG_DEBUGFLAG(DEBUG_ASN1)) @@ -1556,7 +1531,7 @@ static int handle_rrcSetupComplete(const protocol_ctxt_t *const ctxt_pP, return -1; } - uint64_t fiveg_s_TMSI = bitStr_to_uint64(&setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI); + uint64_t fiveg_s_TMSI = BIT_STRING_to_uint64(&setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI); LOG_I(NR_RRC, "Received rrcSetupComplete, 5g_s_TMSI: 0x%lX, amf_set_id: 0x%lX(%ld), amf_pointer: 0x%lX(%ld), 5g TMSI: 0x%X \n", fiveg_s_TMSI, From 3371b53fda828b98bdb94e32ab4b1879638e6650 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 1 Feb 2024 16:55:12 +0100 Subject: [PATCH 19/47] NGAP initial context setup: store NSSAI --- openair3/NGAP/ngap_gNB_handlers.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index fb9952e35c..3999efe622 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -755,6 +755,16 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 NGAP_PDUSessionResourceSetupItemCxtReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.array[i]; msg->pdusession_param[i].pdusession_id = item_p->pDUSessionID; + OCTET_STRING_TO_INT8(&item_p->s_NSSAI.sST, msg->pdusession_param[i].nssai.sst); + if (item_p->s_NSSAI.sD != NULL) { + uint8_t *sd_p = (uint8_t *)&msg->pdusession_param[i].nssai.sd; + sd_p[0] = item_p->s_NSSAI.sD->buf[0]; + sd_p[1] = item_p->s_NSSAI.sD->buf[1]; + sd_p[2] = item_p->s_NSSAI.sD->buf[2]; + } else { + msg->pdusession_param[i].nssai.sd = 0xffffff; + } + if (item_p->nAS_PDU) { allocCopy(&msg->pdusession_param[i].nas_pdu, *item_p->nAS_PDU); } From 8a5a1f2d22c5b8180c99ee78c3fb0167d921ab1b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 17:11:11 +0100 Subject: [PATCH 20/47] NGAP: Correct encoding of AMF Pointer 5G-S-TMSI --- openair3/NGAP/ngap_gNB_nas_procedures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 21144e4beb..9e11cb3e64 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -246,7 +246,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_FiveG_S_TMSI; AMF_SETID_TO_BIT_STRING(UEfirstReq->ue_identity.s_tmsi.amf_set_id, &ie->value.choice.FiveG_S_TMSI.aMFSetID); - AMF_SETID_TO_BIT_STRING(UEfirstReq->ue_identity.s_tmsi.amf_pointer, &ie->value.choice.FiveG_S_TMSI.aMFPointer); + AMF_POINTER_TO_BIT_STRING(UEfirstReq->ue_identity.s_tmsi.amf_pointer, &ie->value.choice.FiveG_S_TMSI.aMFPointer); M_TMSI_TO_OCTET_STRING(UEfirstReq->ue_identity.s_tmsi.m_tmsi, &ie->value.choice.FiveG_S_TMSI.fiveG_TMSI); } From 642b6429a334fd841eca03c64f8f9e3d19e01eda Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 17:13:49 +0100 Subject: [PATCH 21/47] Fix NGAP encoding of PDUsession failed We did not give a cause value, and therefore NGAP's "PDU sessions failed" encoding failed. Give a cause value in all cases, so that this cannot happen anymore. To prevent against this, put an AssertFatal() into the encoder that stops if an internally sent message does not have a correct cause value (we can at least select a default). Print an info message for all failed PDU sessions. In rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(): if a PDU session is already established, don't count it as failed. --- openair2/RRC/NR/rrc_gNB_NGAP.c | 17 ++++++++++------- openair3/NGAP/ngap_gNB_nas_procedures.c | 13 ++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 972148947c..60d5f2c413 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -460,12 +460,13 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(const protocol_ctxt_t *const c resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; } - } else { + } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { + session->status = PDU_SESSION_STATUS_FAILED; + pdusession_failed_t *fail = &resp->pdusessions_failed[pdu_sessions_failed]; + fail->pdusession_id = session->param.pdusession_id; + fail->cause = NGAP_CAUSE_RADIO_NETWORK; + fail->cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID; pdu_sessions_failed++; - resp->pdusessions_failed[pdusession].pdusession_id = session->param.pdusession_id; - // TODO add cause when it will be integrated - resp->pdusessions_failed[pdusession].cause = NGAP_CAUSE_RADIO_NETWORK; - resp->pdusessions_failed[pdusession].cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID; } } @@ -709,9 +710,11 @@ rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP( pdu_sessions_done++; } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { session->status = PDU_SESSION_STATUS_FAILED; - resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = session->param.pdusession_id; + pdusession_failed_t *fail = &resp->pdusessions_failed[pdu_sessions_failed]; + fail->pdusession_id = session->param.pdusession_id; + fail->cause = NGAP_CAUSE_RADIO_NETWORK; + fail->cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID; pdu_sessions_failed++; - // TODO add cause when it will be integrated } resp->nb_of_pdusessions = pdu_sessions_done; resp->nb_of_pdusessions_failed = pdu_sessions_failed; diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 9e11cb3e64..45f5e701e9 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -699,11 +699,11 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r case NGAP_CAUSE_NOTHING: default: - LOG_E(NR_RRC, "Unknown PDU session failure cause %d\n", initial_ctxt_resp_p->pdusessions_failed[i].cause); + AssertFatal(false, "Unknown PDU session failure cause %d\n", initial_ctxt_resp_p->pdusessions_failed[i].cause); break; } - NGAP_DEBUG("initial context setup response: failed pdusession ID %ld\n", item->pDUSessionID); + NGAP_INFO("initial context setup response: failed pdusession ID %ld\n", item->pDUSessionID); asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, &pdusessionUnTransfer); AssertFatal(res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); item->pDUSessionResourceSetupUnsuccessfulTransfer.buf = res.buffer; @@ -931,7 +931,6 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re ie->value.present = NGAP_PDUSessionResourceSetupResponseIEs__value_PR_PDUSessionResourceFailedToSetupListSURes; for (int i = 0; i < pdusession_setup_resp_p->nb_of_pdusessions_failed; i++) { - LOG_W(NGAP,"add a failed session\n"); pdusession_failed_t *pdusession_failed = pdusession_setup_resp_p->pdusessions_failed + i; asn1cSequenceAdd(ie->value.choice.PDUSessionResourceFailedToSetupListSURes.list, NGAP_PDUSessionResourceFailedToSetupItemSURes_t, item); NGAP_PDUSessionResourceSetupUnsuccessfulTransfer_t pdusessionUnTransfer_p = {0}; @@ -968,10 +967,10 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re case NGAP_CAUSE_NOTHING: default: - LOG_E(NR_RRC, "Unknown PDU session failure cause %d\n", pdusession_failed->cause); + AssertFatal(false, "Unknown PDU session failure cause %d\n", pdusession_failed->cause); break; } - NGAP_DEBUG("pdusession setup response: failed pdusession ID %ld\n", item->pDUSessionID); + NGAP_INFO("pdusession setup response: failed pdusession ID %ld\n", item->pDUSessionID); asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, &pdusessionUnTransfer_p); item->pDUSessionResourceSetupUnsuccessfulTransfer.buf = res.buffer; @@ -1132,7 +1131,7 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_ case NGAP_CAUSE_NOTHING: default: - LOG_E(NR_RRC, "Unknown PDU session failure cause %d\n", pdusession_modify_resp_p->pdusessions_failed[i].cause); + AssertFatal(false, "Unknown PDU session failure cause %d\n", pdusession_modify_resp_p->pdusessions_failed[i].cause); break; } @@ -1144,7 +1143,7 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceModifyUnsuccessfulTransfer, pdusessionTransfer_p); - NGAP_DEBUG("pdusession_modify_resp: failed pdusession ID %ld\n", item->pDUSessionID); + NGAP_INFO("pdusession_modify_resp: failed pdusession ID %ld\n", item->pDUSessionID); } } From 1ee89735a22c6db59dd1d1afb644c5b41e4772f2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 11 Oct 2023 09:42:34 +0200 Subject: [PATCH 22/47] Store 5G-S-TMSI from UE if received This commit implements retrieval of 5G-S-TMSI from Parts 1&2, or the entire 5G-S-TMSI, depending on what the UE sends. Further, if it has been retrieved, print a log of all constituent parts of it. The UE-specific variable ng_5G_S_TMSI_Part2 is not needed, as we compute the full 5G-S-TMSI as soon as we have Part2 (and 1). The correct forwarding to the core is implemented in the following commit. --- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB.c | 96 +++++++++++++++++------------------ 2 files changed, 46 insertions(+), 51 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index b0702a2f0d..982de87512 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -277,7 +277,6 @@ typedef struct gNB_RRC_UE_s { /* Information from UE RRC Setup Request */ NR_UE_S_TMSI Initialue_identity_5g_s_TMSI; uint64_t ng_5G_S_TMSI_Part1; - uint16_t ng_5G_S_TMSI_Part2; NR_EstablishmentCause_t establishment_cause; uint32_t rrc_ue_id; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 0e3f534573..3c84737db6 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1213,27 +1213,13 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, } uint64_t s_tmsi_part1 = BIT_STRING_to_uint64(&rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1); + LOG_I(NR_RRC, "Received UE 5G-S-TMSI-Part1 %ld\n", s_tmsi_part1); - // memcpy(((uint8_t *) & random_value) + 3, - // rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1.buf, - // rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1.size); - - if ((ue_context_p = rrc_gNB_ue_context_5g_s_tmsi_exist(rrc, s_tmsi_part1))) { - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - LOG_I(NR_RRC, " 5G-S-TMSI-Part1 exists, old rnti %04x => %04x\n", UE->rnti, msg->crnti); - AssertFatal(false, "not implemented\n"); - - /* replace rnti in the context */ - UE->rnti = msg->crnti; - } else { - LOG_I(NR_RRC, "UE %04x 5G-S-TMSI-Part1 doesn't exist, setting ng_5G_S_TMSI_Part1 => %ld\n", msg->crnti, s_tmsi_part1); - - ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, s_tmsi_part1, msg->gNB_DU_ue_id); - AssertFatal(ue_context_p != NULL, "out of memory\n"); - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - UE->Initialue_identity_5g_s_TMSI.presence = true; - UE->ng_5G_S_TMSI_Part1 = s_tmsi_part1; - } + ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, s_tmsi_part1, msg->gNB_DU_ue_id); + AssertFatal(ue_context_p != NULL, "out of memory\n"); + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + UE->Initialue_identity_5g_s_TMSI.presence = true; + UE->ng_5G_S_TMSI_Part1 = s_tmsi_part1; } else { uint64_t random_value = 0; memcpy(((uint8_t *)&random_value) + 3, @@ -1509,42 +1495,52 @@ static int handle_rrcSetupComplete(const protocol_ctxt_t *const ctxt_pP, NR_RRCSetupComplete_IEs_t *setup_complete_ies = setup_complete->criticalExtensions.choice.rrcSetupComplete; if (setup_complete_ies->ng_5G_S_TMSI_Value != NULL) { + uint64_t fiveg_s_TMSI = 0; if (setup_complete_ies->ng_5G_S_TMSI_Value->present == NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value_PR_ng_5G_S_TMSI_Part2) { - if (setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI_Part2.size != 2) { - LOG_E(NR_RRC, - "wrong ng_5G_S_TMSI_Part2 size, expected 2, provided %lu", - (long unsigned int) - setup_complete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI_Part2.size); + const BIT_STRING_t *part2 = &setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI_Part2; + if (part2->size != 2) { + LOG_E(NR_RRC, "wrong ng_5G_S_TMSI_Part2 size, expected 2, provided %lu", part2->size); return -1; } - if (UE->ng_5G_S_TMSI_Part1 != 0) { - UE->ng_5G_S_TMSI_Part2 = BIT_STRING_to_uint16(&setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI_Part2); - } - - /* TODO */ - } else if (setup_complete_ies->ng_5G_S_TMSI_Value->present == NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value_PR_ng_5G_S_TMSI) { - if (setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.size != 6) { - LOG_E(NR_RRC, - "wrong ng_5G_S_TMSI size, expected 6, provided %lu", - (long unsigned int)setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.size); - return -1; - } - - uint64_t fiveg_s_TMSI = BIT_STRING_to_uint64(&setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI); - LOG_I(NR_RRC, - "Received rrcSetupComplete, 5g_s_TMSI: 0x%lX, amf_set_id: 0x%lX(%ld), amf_pointer: 0x%lX(%ld), 5g TMSI: 0x%X \n", - fiveg_s_TMSI, - fiveg_s_TMSI >> 38, - fiveg_s_TMSI >> 38, - (fiveg_s_TMSI >> 32) & 0x3F, - (fiveg_s_TMSI >> 32) & 0x3F, - (uint32_t)fiveg_s_TMSI); if (UE->Initialue_identity_5g_s_TMSI.presence) { - UE->Initialue_identity_5g_s_TMSI.amf_set_id = fiveg_s_TMSI >> 38; - UE->Initialue_identity_5g_s_TMSI.amf_pointer = (fiveg_s_TMSI >> 32) & 0x3F; - UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi = (uint32_t)fiveg_s_TMSI; + uint16_t stmsi_part2 = BIT_STRING_to_uint16(part2); + LOG_I(RRC, "s_tmsi part2 %d (%02x %02x)\n", stmsi_part2, part2->buf[0], part2->buf[1]); + // Part2 is leftmost 9, Part1 is rightmost 39 bits of 5G-S-TMSI + fiveg_s_TMSI = ((uint64_t) stmsi_part2) << 39 | UE->ng_5G_S_TMSI_Part1; + } else { + LOG_W(RRC, "UE %d received 5G-S-TMSI-Part2, but no 5G-S-TMSI-Part1 present, won't send 5G-S-TMSI to core\n", UE->rrc_ue_id); + UE->Initialue_identity_5g_s_TMSI.presence = false; } + } else if (setup_complete_ies->ng_5G_S_TMSI_Value->present == NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value_PR_ng_5G_S_TMSI) { + const NR_NG_5G_S_TMSI_t *bs_stmsi = &setup_complete_ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI; + if (bs_stmsi->size != 6) { + LOG_E(NR_RRC, "wrong ng_5G_S_TMSI size, expected 6, provided %lu", bs_stmsi->size); + return -1; + } + + fiveg_s_TMSI = BIT_STRING_to_uint64(bs_stmsi); + UE->Initialue_identity_5g_s_TMSI.presence = true; + } + + if (UE->Initialue_identity_5g_s_TMSI.presence) { + uint16_t amf_set_id = fiveg_s_TMSI >> 38; + uint8_t amf_pointer = (fiveg_s_TMSI >> 32) & 0x3F; + uint32_t fiveg_tmsi = (uint32_t) fiveg_s_TMSI; + LOG_I(NR_RRC, + "5g_s_TMSI: 0x%lX, amf_set_id: 0x%X (%d), amf_pointer: 0x%X (%d), 5g TMSI: 0x%X \n", + fiveg_s_TMSI, + amf_set_id, + amf_set_id, + amf_pointer, + amf_pointer, + fiveg_tmsi); + UE->Initialue_identity_5g_s_TMSI.amf_set_id = amf_set_id; + UE->Initialue_identity_5g_s_TMSI.amf_pointer = amf_pointer; + UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi = fiveg_tmsi; + + // update random identity with 5G-S-TMSI, which only contained Part1 of it + UE->random_ue_identity = fiveg_s_TMSI; } } From f9a8498566cba61829bf995bf2a600d84ee14bf3 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 16:03:11 +0100 Subject: [PATCH 23/47] RRC: forward 5G-S-TMSI for NGAP Initial UE Message Only fill the 5G-S-TMSI if if is present, and set the bit in the presenceMask. --- openair2/RRC/NR/rrc_gNB_NGAP.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 60d5f2c413..8bc76c570c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -201,10 +201,13 @@ rrc_gNB_send_NGAP_NAS_FIRST_REQ( /* Fill UE identities with available information */ req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_NONE; - /* Fill s-TMSI */ - req->ue_identity.s_tmsi.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id; - req->ue_identity.s_tmsi.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer; - req->ue_identity.s_tmsi.m_tmsi = UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi; + if (UE->Initialue_identity_5g_s_TMSI.presence) { + /* Fill s-TMSI */ + req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_FiveG_s_tmsi; + req->ue_identity.s_tmsi.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id; + req->ue_identity.s_tmsi.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer; + req->ue_identity.s_tmsi.m_tmsi = UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi; + } /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */ int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; From 04c6c34d24a7d3834a8751796ad61b14a606de62 Mon Sep 17 00:00:00 2001 From: Luis Pereira Date: Thu, 25 Jan 2024 09:49:08 +0100 Subject: [PATCH 24/47] NR MAC stats: make more compact, update CI checker - show MAC bytes in one line - add MCS table idx - show ulsch errors before ulsch DTX (as in DL) - show if UE in-sync/out-of-sync - show CU UE ID next to RNTI to stats Since we modify the format of the statistics, fix the format in the retx checkers of the CI. --- ci-scripts/ran.py | 4 ++-- openair2/LAYER2/NR_MAC_gNB/main.c | 33 ++++++++++++++++++------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index fc6bf1b42f..17a8b54d6d 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -992,7 +992,7 @@ class RANManagement(): NSA_RAPROC_PUSCH_check = 1 # Collect information on UE DLSCH and ULSCH statistics - keys = {'dlsch_rounds','dlsch_total_bytes','ulsch_rounds','ulsch_total_bytes_scheduled'} + keys = {'dlsch_rounds','ulsch_rounds'} for k in keys: result = re.search(k, line) if result is None: @@ -1161,7 +1161,7 @@ class RANManagement(): dlcheckers = [] if 'd_retx_th' not in checkers else checkers['d_retx_th'] retx_status[ue]['dl'] = self._analyzeUeRetx(dlulstat['dlsch_rounds'], dlcheckers, r'^.*dlsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+dlsch_errors\s+(\d+)') ulcheckers = [] if 'u_retx_th' not in checkers else checkers['u_retx_th'] - retx_status[ue]['ul'] = self._analyzeUeRetx(dlulstat['ulsch_rounds'], ulcheckers, r'^.*ulsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+.*,\s+ulsch_errors\s+(\d+)') + retx_status[ue]['ul'] = self._analyzeUeRetx(dlulstat['ulsch_rounds'], ulcheckers, r'^.*ulsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+ulsch_errors\s+(\d+)') #real time statistics diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index a1e8af3e5f..72689dd90d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -85,7 +85,6 @@ void clear_mac_stats(gNB_MAC_INST *gNB) { size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp) { - int num = 1; const char *begin = output; const char *end = output + strlen; @@ -99,11 +98,19 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset NR_mac_stats_t *stats = &UE->mac_stats; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; + output += snprintf(output, end - output, "UE RNTI %04x CU-UE-ID ", UE->rnti); + if (du_exists_f1_ue_data(UE->rnti)) { + f1_ue_data_t ued = du_get_f1_ue_data(UE->rnti); + output += snprintf(output, end - output, "%d", ued.secondary_ue); + } else { + output += snprintf(output, end-output, "(none)"); + } + + bool in_sync = !sched_ctrl->ul_failure; output += snprintf(output, end - output, - "UE RNTI %04x (%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", - UE->rnti, - num++, + " %s PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", + in_sync ? "in-sync" : "out-of-sync", sched_ctrl->ph, sched_ctrl->pcmax, avg_rsrp, @@ -132,19 +139,16 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset output += snprintf(output, end - output, - ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS %d\n", + ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS (%d) %d\n", stats->dl.errors, stats->pucch0_DTX, sched_ctrl->dl_bler_stats.bler, + UE->current_DL_BWP.mcsTableIdx, sched_ctrl->dl_bler_stats.mcs); if (reset_rsrp) { stats->num_rsrp_meas = 0; stats->cumul_rsrp = 0; } - output += snprintf(output, - end - output, - "UE %04x: dlsch_total_bytes %"PRIu64"\n", - UE->rnti, stats->dl.total_bytes); output += snprintf(output, end - output, "UE %04x: ulsch_rounds ", UE->rnti); @@ -154,16 +158,17 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset output += snprintf(output, end - output, - ", ulsch_DTX %d, ulsch_errors %"PRIu64", BLER %.5f MCS %d\n", - stats->ulsch_DTX, + ", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d\n", stats->ul.errors, + stats->ulsch_DTX, sched_ctrl->ul_bler_stats.bler, + UE->current_UL_BWP.mcs_table, sched_ctrl->ul_bler_stats.mcs); + output += snprintf(output, end - output, - "UE %04x: ulsch_total_bytes_scheduled %"PRIu64", ulsch_total_bytes_received %"PRIu64"\n", - UE->rnti, - stats->ulsch_total_bytes_scheduled, stats->ul.total_bytes); + "UE %04x: MAC: TX %14"PRIu64" RX %14"PRIu64" bytes\n", + UE->rnti, stats->dl.total_bytes, stats->ul.total_bytes); for (int i = 0; i < sched_ctrl->dl_lc_num; i++) { int lc_id = sched_ctrl->dl_lc_ids[i]; From 34b5e592f0e10cf72df4dd6484da9acf60734d5f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 19 Jan 2024 16:42:05 +0100 Subject: [PATCH 25/47] Add function to activate SRBs in gNB RRC Create a single function to activate an SRB. This function derives the corresponding keys, triggers the setup in PDCP, and marks the SRB as set up, instead of doing all of this common functionality in individual steps. Use it at the corresponding places. --- openair2/RRC/NR/rrc_gNB.c | 53 ++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 3c84737db6..46db206991 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -442,6 +442,38 @@ static void freeSRBlist(NR_SRB_ToAddModList_t *l) LOG_E(NR_RRC, "Call free SRB list on NULL pointer\n"); } +static void activate_srb(gNB_RRC_UE_t *UE, int srb_id) +{ + AssertFatal(srb_id == 1 || srb_id == 2, "handling only SRB 1 or 2\n"); + if (UE->Srb[srb_id].Active == 1) { + LOG_W(RRC, "UE %d SRB %d already activated\n", UE->rrc_ue_id, srb_id); + return; + } + LOG_I(RRC, "activate SRB %d of UE %d\n", srb_id, UE->rrc_ue_id); + UE->Srb[srb_id].Active = 1; + + NR_SRB_ToAddModList_t *list = CALLOC(sizeof(*list), 1); + asn1cSequenceAdd(list->list, NR_SRB_ToAddMod_t, srb); + srb->srb_Identity = srb_id; + + if (srb_id == 1) { + nr_pdcp_add_srbs(true, UE->rrc_ue_id, list, 0, NULL, NULL); + } else { + uint8_t kRRCenc[16] = {0}; + uint8_t kRRCint[16] = {0}; + nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kRRCenc); + nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, kRRCint); + + nr_pdcp_add_srbs(true, + UE->rrc_ue_id, + list, + (UE->integrity_algorithm << 4) | UE->ciphering_algorithm, + kRRCenc, + kRRCint); + } + freeSRBlist(list); +} + //----------------------------------------------------------------------------- static void rrc_gNB_generate_RRCSetup(instance_t instance, rnti_t rnti, @@ -463,12 +495,7 @@ static void rrc_gNB_generate_RRCSetup(instance_t instance, AssertFatal(size > 0, "do_RRCSetup failed\n"); AssertFatal(size <= 1024, "memory corruption\n"); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, - (char *)buf, - size, - "[MSG] RRC Setup\n"); - nr_pdcp_add_srbs(true, ue_p->rrc_ue_id, SRBs, 0, NULL, NULL); - + 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); @@ -944,14 +971,6 @@ static void rrc_gNB_process_RRCReconfigurationComplete(const protocol_ctxt_t *co LOG_D(NR_RRC, "Configuring PDCP DRBs/SRBs for UE %04x\n", ue_p->rnti); ue_context_pP->ue_context.ue_reconfiguration_after_reestablishment_counter++; - NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false); - nr_pdcp_add_srbs(ctxt_pP->enb_flag, - ue_p->rrc_ue_id, - SRBs, - (ue_p->integrity_algorithm << 4) | ue_p->ciphering_algorithm, - kRRCenc, - kRRCint); - freeSRBlist(SRBs); nr_pdcp_add_drbs(ctxt_pP->enb_flag, ue_p->rrc_ue_id, DRB_configList, @@ -1235,7 +1254,7 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, gNB_RRC_UE_t *UE = &ue_context_p->ue_context; UE = &ue_context_p->ue_context; UE->establishment_cause = rrcSetupRequest->establishmentCause; - UE->Srb[1].Active = 1; + activate_srb(UE, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); } @@ -1330,7 +1349,7 @@ fallback_rrc_setup: random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); - new->ue_context.Srb[1].Active = 1; + activate_srb(&new->ue_context, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); return; } @@ -2114,7 +2133,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp int nb_srb = 0; f1ap_srb_to_be_setup_t srbs[1]; if (UE->Srb[2].Active == 0) { - UE->Srb[2].Active = 1; + activate_srb(UE, 2); nb_srb = 1; srbs[0].srb_id = 2; srbs[0].lcid = 2; From 4b3b6b1e5e505495ad7631cc32c40be0c8fdeeb2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 19 Jan 2024 16:37:42 +0100 Subject: [PATCH 26/47] createDRBlist(): return NULL if no active DRB If there are no active bearers, the function previously returned an empty list. Return NULL if there are no bearers, so it is safe to call this function even when no bearers are present. We can also pass it every time to do_RRCReconfiguration(), which will not add an empty list for DRBs. --- openair2/RRC/NR/rrc_gNB.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 46db206991..25c131e4aa 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -429,6 +429,10 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) asn1cSeqAdd(&DRB_configList->list, DRB_config); } } + if (DRB_configList->list.count == 0) { + free(DRB_configList); + return NULL; + } return DRB_configList; } From 3d0a7ecf28ee6f2ac7ba3a9d7f06c80e4b6ddc77 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 11:33:43 +0100 Subject: [PATCH 27/47] DRB: do not activate in RRC, this is done through E1 --- openair2/RRC/NR/rrc_gNB.c | 62 +-------------------------------------- 1 file changed, 1 insertion(+), 61 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 25c131e4aa..b627984959 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -955,81 +955,21 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( static void rrc_gNB_process_RRCReconfigurationComplete(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, const uint8_t xid) { int drb_id; - uint8_t kRRCenc[16] = {0}; - uint8_t kRRCint[16] = {0}; - uint8_t kUPenc[16] = {0}; - uint8_t kUPint[16] = {0}; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; NR_DRB_ToAddModList_t *DRB_configList = createDRBlist(ue_p, false); - /* Derive the keys from kgnb */ - if (DRB_configList != NULL) { - nr_derive_key(UP_ENC_ALG, ue_p->ciphering_algorithm, ue_p->kgnb, kUPenc); - nr_derive_key(UP_INT_ALG, ue_p->integrity_algorithm, ue_p->kgnb, kUPint); - } - - nr_derive_key(RRC_ENC_ALG, ue_p->ciphering_algorithm, ue_p->kgnb, kRRCenc); - nr_derive_key(RRC_INT_ALG, ue_p->integrity_algorithm, ue_p->kgnb, kRRCint); - /* Refresh SRBs/DRBs */ LOG_D(NR_RRC, "Configuring PDCP DRBs/SRBs for UE %04x\n", ue_p->rnti); ue_context_pP->ue_context.ue_reconfiguration_after_reestablishment_counter++; - nr_pdcp_add_drbs(ctxt_pP->enb_flag, - ue_p->rrc_ue_id, - DRB_configList, - (ue_p->integrity_algorithm << 4) | ue_p->ciphering_algorithm, - kUPenc, - kUPint); - /* Loop through DRBs and establish if necessary */ if (DRB_configList != NULL) { for (int i = 0; i < DRB_configList->list.count; i++) { if (DRB_configList->list.array[i]) { drb_id = (int)DRB_configList->list.array[i]->drb_Identity; - LOG_A(NR_RRC, - "[gNB %d] Frame %d : Logical Channel UL-DCCH, Received NR_RRCReconfigurationComplete from UE rnti %lx, reconfiguring DRB %d\n", - ctxt_pP->module_id, - ctxt_pP->frame, - ctxt_pP->rntiMaybeUEid, - (int)DRB_configList->list.array[i]->drb_Identity); - //(int)*DRB_configList->list.array[i]->pdcp_Config->moreThanOneRLC->primaryPath.logicalChannel); - if (ue_p->DRB_active[drb_id - 1] == 0) { ue_p->DRB_active[drb_id - 1] = DRB_ACTIVE; - LOG_D(NR_RRC, "[gNB %d] Frame %d: Establish RLC UM Bidirectional, DRB %d Active\n", - ctxt_pP->module_id, ctxt_pP->frame, (int)DRB_configList->list.array[i]->drb_Identity); - - LOG_D(NR_RRC, - PROTOCOL_NR_RRC_CTXT_UE_FMT" RRC_gNB --- MAC_CONFIG_REQ (DRB) ---> MAC_gNB\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); - - //if (DRB_configList->list.array[i]->pdcp_Config->moreThanOneRLC->primaryPath.logicalChannel) { - // nr_DRB2LCHAN[i] = (uint8_t) * DRB_configList->list.array[i]->pdcp_Config->moreThanOneRLC->primaryPath.logicalChannel; - //} - - // rrc_mac_config_req_eNB - } else { // remove LCHAN from MAC/PHY - if (ue_p->DRB_active[drb_id] == 1) { - /* TODO : It may be needed if gNB goes into full stack working. */ - // DRB has just been removed so remove RLC + PDCP for DRB - /* rrc_pdcp_config_req (ctxt_pP->module_id, frameP, 1, CONFIG_ACTION_REMOVE, - (ue_mod_idP * NB_RB_MAX) + DRB2LCHAN[i],UNDEF_SECURITY_MODE); - */ - /*rrc_rlc_config_req(ctxt_pP, - SRB_FLAG_NO, - MBMS_FLAG_NO, - CONFIG_ACTION_REMOVE, - nr_DRB2LCHAN[i]);*/ - } - - // ue_p->DRB_active[drb_id] = 0; - LOG_D(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" RRC_eNB --- MAC_CONFIG_REQ (DRB) ---> MAC_eNB\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP)); - - // rrc_mac_config_req_eNB - - } // end else of if (ue_p->DRB_active[drb_id] == 0) + } } // end if (DRB_configList->list.array[i]) } // end for (int i = 0; i < DRB_configList->list.count; i++) From 37929dca6cc2f358f252d368afbf032badca772f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 19 Jan 2024 16:41:36 +0100 Subject: [PATCH 28/47] Remove SRBs variable: it is simply not used --- openair2/RRC/NR/rrc_gNB.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b627984959..95bb21f1f3 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -992,7 +992,6 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context uint8_t buffer[RRC_BUF_SIZE] = {0}; uint8_t xid = rrc_gNB_get_next_transaction_identifier(module_id); ue_p->xids[xid] = RRC_REESTABLISH; - NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, true); const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; uint32_t ssb_arfcn = get_ssb_arfcn(cell_info, du->mib, du->sib1); int size = do_RRCReestablishment(ue_context_pP, buffer, RRC_BUF_SIZE, xid, cell_info->nr_pci, ssb_arfcn); @@ -1008,7 +1007,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context nr_derive_key(RRC_ENC_ALG, ue_p->ciphering_algorithm, ue_p->kgnb, kRRCenc); nr_derive_key(RRC_INT_ALG, ue_p->integrity_algorithm, ue_p->kgnb, kRRCint); - freeSRBlist(SRBs); + LOG_I(NR_RRC, "Set PDCP security UE %d RNTI %04x nca %ld nia %d in RRCReestablishment\n", ue_p->rrc_ue_id, ue_p->rnti, ue_p->ciphering_algorithm, ue_p->integrity_algorithm); uint8_t security_mode = enable_ciphering ? ue_p->ciphering_algorithm | (ue_p->integrity_algorithm << 4) : 0 | (ue_p->integrity_algorithm << 4); From 1c2e4c711872d6e593ecc2d7525da8ccc2995342 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 4 Jan 2024 16:45:39 +0100 Subject: [PATCH 29/47] Remove drb_active array The drb_active array keeps track of active DRBs. However, it only replicates some of the information in established_drbs, and could lead to a reuse of DRB IDs when two bearers are to be set up. Consider the following: 1. trigger first DRB creation at RRC 2. DRB ID chosen from free drb_active entry 3. trigger second DRB creation at RRC -> The first reconfiguration has not been acknowledged -> drb_active is not marked as DRB_ACTIVE 4. The second DRB ID is chosen from a free drb_active entry, which is the same as in 2. By reusing established_drbs everywhere, this cannot happen, as we 1. select the DRB to be used using next_available_drb() and then 2. use generateDRB(), which marks the DRB used all from within fill_DRB_configList, which gives a new DRB. The logic is still overly complex, though. --- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB.c | 20 -------------------- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 9 ++++----- 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 982de87512..5846383bdc 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -237,7 +237,6 @@ typedef enum { typedef struct gNB_RRC_UE_s { drb_t established_drbs[MAX_DRBS_PER_UE]; - uint8_t DRB_active[MAX_DRBS_PER_UE]; NR_DRB_ToReleaseList_t *DRB_ReleaseList; NR_SRB_INFO_TABLE_ENTRY Srb[maxSRBs]; // 3gpp max is 3 SRBs, number 1..3, we waste the entry 0 for code simplicity diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 95bb21f1f3..b5d8deee2e 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -954,27 +954,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( */ static void rrc_gNB_process_RRCReconfigurationComplete(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, const uint8_t xid) { - int drb_id; - gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - NR_DRB_ToAddModList_t *DRB_configList = createDRBlist(ue_p, false); - - /* Refresh SRBs/DRBs */ - LOG_D(NR_RRC, "Configuring PDCP DRBs/SRBs for UE %04x\n", ue_p->rnti); ue_context_pP->ue_context.ue_reconfiguration_after_reestablishment_counter++; - - /* Loop through DRBs and establish if necessary */ - if (DRB_configList != NULL) { - for (int i = 0; i < DRB_configList->list.count; i++) { - if (DRB_configList->list.array[i]) { - drb_id = (int)DRB_configList->list.array[i]->drb_Identity; - if (ue_p->DRB_active[drb_id - 1] == 0) { - ue_p->DRB_active[drb_id - 1] = DRB_ACTIVE; - } - } // end if (DRB_configList->list.array[i]) - } // end for (int i = 0; i < DRB_configList->list.count; i++) - - } // end if DRB_configList != NULL - freeDRBlist(DRB_configList); } //----------------------------------------------------------------------------- diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 77ad016350..efff9f2d8a 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -154,16 +154,15 @@ uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession } /* GBR Flow or a Non-GBR DRB does not exist in the same PDU Session, find an available DRB */ for (drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) - if (ue->DRB_active[drb_id] == DRB_INACTIVE) + if (ue->established_drbs[drb_id].status == DRB_INACTIVE) return drb_id + 1; /* From this point, we need to handle the case that all DRBs are already used by the UE. */ LOG_E(RRC, "Error - All the DRBs are used - Handle this\n"); return DRB_INACTIVE; } -bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) { +bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) +{ DevAssert(drb_id > 0); - if(ue->DRB_active[drb_id-1] == DRB_ACTIVE) - return true; - return false; + return ue->established_drbs[drb_id - 1].status == DRB_ACTIVE; } From d5257ca82013bd60c8d131e3e9c8415ceb6500d7 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 5 Jan 2024 11:55:04 +0100 Subject: [PATCH 30/47] Remove superfluous function, rename variable The function rrc_gNB_process_RRCReconfigurationComplete() does almost nothing, we can delete it. The variable name ue_reconfiguration_after_reestablishment_counter is misleading, as it counts all reconfigurations; rename to make it clear. --- common/utils/telnetsrv/telnetsrv_ci.c | 4 ++-- openair2/RRC/NR/nr_rrc_defs.h | 2 +- openair2/RRC/NR/rrc_gNB.c | 11 +---------- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index 943a3eec29..0f56f72cfd 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -92,10 +92,10 @@ int get_reestab_count(char *buf, int debug, telnet_printfunc_t prnt) ERROR_MSG_RET("could not find UE with RNTI %04x in RRC\n"); } - prnt("UE RNTI %04x reestab %d reconf_after_reestab %d\n", + prnt("UE RNTI %04x reestab %d reconfig %d\n", ue->ue_context.rnti, ue->ue_context.ue_reestablishment_counter, - ue->ue_context.ue_reconfiguration_after_reestablishment_counter); + ue->ue_context.ue_reconfiguration_counter); return 0; } diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 5846383bdc..becf1b75ed 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -300,7 +300,7 @@ typedef struct gNB_RRC_UE_s { uint8_t e_rab_release_command_flag; uint32_t ue_rrc_inactivity_timer; uint32_t ue_reestablishment_counter; - uint32_t ue_reconfiguration_after_reestablishment_counter; + uint32_t ue_reconfiguration_counter; NR_CellGroupId_t cellGroupId; struct NR_SpCellConfig *spCellConfig; struct NR_CellGroupConfig__sCellToAddModList *sCellconfig; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b5d8deee2e..bc4702e19b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -948,15 +948,6 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size); } -//----------------------------------------------------------------------------- -/* -* Process the RRC Reconfiguration Complete from the UE -*/ -static void rrc_gNB_process_RRCReconfigurationComplete(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, const uint8_t xid) -{ - ue_context_pP->ue_context.ue_reconfiguration_after_reestablishment_counter++; -} - //----------------------------------------------------------------------------- static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context_pP, const uint8_t *masterCellGroup_from_DU, @@ -1500,7 +1491,7 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ gNB_RRC_UE_t *UE = &ue_context_p->ue_context; uint8_t xid = reconfig_complete->rrc_TransactionIdentifier; - rrc_gNB_process_RRCReconfigurationComplete(ctxt_pP, ue_context_p, xid); + UE->ue_reconfiguration_counter++; bool successful_reconfig = true; switch (UE->xids[xid]) { From 5258acbf450187b532c859f54ab3274d81c557df Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 18 Jan 2024 16:50:33 +0100 Subject: [PATCH 31/47] Remove unused variables in RRC --- openair2/RRC/NR/rrc_gNB.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index bc4702e19b..c6f2d3dc97 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -658,19 +658,15 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); - int drb_id_to_setup_start = 1; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(ue_p); - int nb_drb_to_setup = DRB_configList ? DRB_configList->list.count : 0; ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = NULL; NR_DedicatedNAS_Message_t *dedicatedNAS_Message = NULL; dedicatedNAS_MessageList = CALLOC(1, sizeof(struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList)); + int nb_drb_to_setup = DRB_configList ? DRB_configList->list.count : 0; for (int i=0; i < nb_drb_to_setup; i++) { - NR_DRB_ToAddMod_t *DRB_config = DRB_configList->list.array[i]; - if (drb_id_to_setup_start == 1) - drb_id_to_setup_start = DRB_config->drb_Identity; int j = ue_p->nb_of_pdusessions - 1; AssertFatal(j >= 0, ""); if (ue_p->pduSession[j].param.nas_pdu.buffer != NULL) { From 2494a7bc7cd44317f95ea2ff1790c12a64193d8f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 09:53:02 +0100 Subject: [PATCH 32/47] Remove unused variables --- openair2/RRC/NR/nr_rrc_defs.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index becf1b75ed..1db349f003 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -301,14 +301,7 @@ typedef struct gNB_RRC_UE_s { uint32_t ue_rrc_inactivity_timer; uint32_t ue_reestablishment_counter; uint32_t ue_reconfiguration_counter; - NR_CellGroupId_t cellGroupId; struct NR_SpCellConfig *spCellConfig; - struct NR_CellGroupConfig__sCellToAddModList *sCellconfig; - struct NR_CellGroupConfig__sCellToReleaseList *sCellconfigRelease; - struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_BearerBonfig; - struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_BearerRelease; - struct NR_MAC_CellGroupConfig *mac_CellGroupConfig; - struct NR_PhysicalCellGroupConfig *physicalCellGroupConfig; /* Nas Pdu */ ngap_pdu_t nas_pdu; From ce4ec2965bfa81a81e9211535e59d1d958cbf5ed Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2024 10:33:36 +0100 Subject: [PATCH 33/47] E1 bearer ctxt setup handler: correct AssertFatal() The number of tunnels corresponds to number of DRBs, so correctly compare tunnels and DRBs. --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 231db3f548..d113905c0a 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -184,7 +184,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) sdap_data_req, &resp_n3); AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n"); - AssertFatal(resp_n3.num_tunnels == req->numPDUSessions, "could not create all tunnels\n"); + AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n"); resp_pdu->teId = resp_n3.gnb_NGu_teid[i]; memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4); From 4c7080ec3f5034f2732817bf4bcd25a39a2ad255 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 1 Feb 2024 16:38:24 +0100 Subject: [PATCH 34/47] E1 bearer ctx handler: correctly index (single) DRB --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index d113905c0a..ec4dc7d167 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -185,7 +185,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) &resp_n3); AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n"); AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n"); - resp_pdu->teId = resp_n3.gnb_NGu_teid[i]; + resp_pdu->teId = resp_n3.gnb_NGu_teid[0]; memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4); // create PDCP bearers. This will also create SDAP bearers From 2800203eff9ae7b39c8d15f899fd3f781e56364f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 16:56:11 +0100 Subject: [PATCH 35/47] Provide means to look-up if UE has a CU-UP It might happen that a UE has no CU-UP (e.g., never requested a PDU session). When triggering a release, we previously and implicitly associated a CU-UP in that case. That is not good, and confusing. This commit adds a function to look up if the UE has an associated CU-UP. We only send a release if it is the case. The function get_existing_cuup_for_ue() now instead verifies that a CU-UP exist, and does not implicitly create an association (which might be unwanted, see above). --- openair2/RRC/NR/nr_rrc_proto.h | 1 + openair2/RRC/NR/rrc_gNB.c | 16 ++++++++++------ openair2/RRC/NR/rrc_gNB_cuup.c | 12 +++++++----- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 45cb2d3439..7c2374acfa 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -125,6 +125,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP); +bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd); int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c6f2d3dc97..aed3c87a60 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2542,12 +2542,16 @@ rrc_gNB_generate_RRCRelease( deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd, .assoc_id = ue_data.du_assoc_id}; nr_pdcp_data_req_srb(ctxt_pP->rntiMaybeUEid, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data); - sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); - e1ap_bearer_release_cmd_t cmd = { - .gNB_cu_cp_ue_id = UE->rrc_ue_id, - .gNB_cu_up_ue_id = UE->rrc_ue_id, - }; - rrc->cucp_cuup.bearer_context_release(assoc_id, &cmd); + /* a UE might not be associated to a CU-UP if it never requested a PDU + * session (intentionally, or because of erros) */ + if (ue_associated_to_cuup(rrc, UE)) { + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); + e1ap_bearer_release_cmd_t cmd = { + .gNB_cu_cp_ue_id = UE->rrc_ue_id, + .gNB_cu_up_ue_id = UE->rrc_ue_id, + }; + rrc->cucp_cuup.bearer_context_release(assoc_id, &cmd); + } /* UE will be freed after UE context release complete */ } diff --git a/openair2/RRC/NR/rrc_gNB_cuup.c b/openair2/RRC/NR/rrc_gNB_cuup.c index 6751739cac..d37a1f430b 100644 --- a/openair2/RRC/NR/rrc_gNB_cuup.c +++ b/openair2/RRC/NR/rrc_gNB_cuup.c @@ -75,14 +75,16 @@ static const nr_rrc_cuup_container_t *select_cuup_round_robin(size_t n_t, const return NULL; } +bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue) +{ + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); + return ue_data.e1_assoc_id != 0; +} + sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue) { f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); - if (ue_data.e1_assoc_id == 0) { - LOG_W(RRC, "UE %d should be associated to CU-UP, but is not\n", ue->rrc_ue_id); - /* we could possibly check the SST/SD from the PDU session */ - return get_new_cuup_for_ue(rrc, ue, 0, 0); - } + AssertFatal(ue_data.e1_assoc_id != 0, "UE %d should be associated to CU-UP, but is not\n", ue->rrc_ue_id); LOG_D(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id); return ue_data.e1_assoc_id; } From a47eab526261118870cb4ba18b49504541124778 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 12:11:49 +0100 Subject: [PATCH 36/47] F1 UE Ctxt modification: forward multiple PDU sessions, including NSSAI --- openair2/RRC/NR/rrc_gNB.c | 77 +++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index aed3c87a60..e3cd14efe8 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1998,45 +1998,52 @@ 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 */ - int nb_drb = resp->pduSession[0].numDRBSetup; - f1ap_drb_to_be_setup_t drbs[nb_drb]; - rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, resp->pduSession[0].id, false); - DevAssert(RRC_pduSession); - for (int i = 0; i < nb_drb; i++) { - DRB_nGRAN_setup_t *drb_config = &resp->pduSession[0].DRBnGRanList[i]; - drbs[i].drb_id = resp->pduSession[0].DRBnGRanList[i].id; - drbs[i].rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; - drbs[i].up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; - drbs[i].up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drbs[i].up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; - drbs[i].up_ul_tnl_length = 1; + 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; - /* 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"); - drbs[i].drb_info.flows_to_be_setup_length = nb_qos_flows; - drbs[i].drb_info.flows_mapped_to_drb = (f1ap_flows_mapped_to_drb_t *)calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t)); - AssertFatal(drbs[i].drb_info.flows_mapped_to_drb, "could not allocate memory\n"); - for (int j = 0; j < nb_qos_flows; j++) { - drbs[i].drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi; + drb->nssai = RRC_pduSession->param.nssai; - pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession); - f1ap_qos_characteristics_t *qos_char = &drbs[i].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; + /* 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 */ - drbs[i].drb_info.drb_qos = drbs[i].drb_info.flows_mapped_to_drb[0].qos_params; + /* 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 */ - drbs[i].nssai = RRC_pduSession->param.nssai; + /* pass NSSAI info to MAC */ + drb->nssai = RRC_pduSession->param.nssai; + + nb_drb++; + } } /* Instruction towards the DU for SRB2 configuration */ From f81ec9c2cc13cf8a8cc5a1fde99265bcad96fe7a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 18:05:18 +0100 Subject: [PATCH 37/47] Simplify RRC DRB handling code Prior to this commit, the handling of DRBs is complex: first the RRC "guessed" a DRB ID when setting up DRBs via E1AP (in rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ()), and later chose one for real in fill_DRB_Configlist() (called in rrc_gNB_generate_dedicatedRRCReconfiguration()). To simplify, remove fill_DRB_Configlist(), and instead allocate the DRB using generateDRB() before sending the message via E1AP, in rrc_gNB_generate_dedicatedRRCReconfiguration(). The rest of the logic is the same. For PDU sessions, always mark PDU sessions as "done" to match pdu session state logic. --- openair2/RRC/NR/rrc_gNB.c | 125 +++++----------------- openair2/RRC/NR/rrc_gNB_NGAP.c | 33 ++++-- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 133 ++++++++++++------------ openair2/RRC/NR/rrc_gNB_radio_bearers.h | 28 +++-- 4 files changed, 136 insertions(+), 183 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e3cd14efe8..377e15bbab 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -121,73 +121,6 @@ mui_t rrc_gNB_mui = 0; ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// -NR_DRB_ToAddModList_t *fill_DRB_configList(gNB_RRC_UE_t *ue) -{ - gNB_RRC_INST *rrc = RC.nrrrc[0]; - if (ue->nb_of_pdusessions == 0) - return NULL; - int nb_drb_to_setup = rrc->configuration.drbs; - long drb_priority[MAX_DRBS_PER_UE] = {0}; - uint8_t drb_id_to_setup_start = 0; - NR_DRB_ToAddModList_t *DRB_configList = CALLOC(sizeof(*DRB_configList), 1); - for (int i = 0; i < ue->nb_of_pdusessions; i++) { - if (ue->pduSession[i].status >= PDU_SESSION_STATUS_DONE) { - continue; - } - LOG_I(NR_RRC, "adding rnti %x pdusession %d, nb drb %d\n", ue->rnti, ue->pduSession[i].param.pdusession_id, nb_drb_to_setup); - for (long drb_id_add = 1; drb_id_add <= nb_drb_to_setup; drb_id_add++) { - uint8_t drb_id; - // Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping - for (int qos_flow_index = 0; qos_flow_index < ue->pduSession[i].param.nb_qos; qos_flow_index++) { - switch (ue->pduSession[i].param.qos[qos_flow_index].fiveQI) { - case 1 ... 4: /* GBR */ - drb_id = next_available_drb(ue, &ue->pduSession[i], GBR_FLOW); - break; - case 5 ... 9: /* Non-GBR */ - if (rrc->configuration.drbs > 1) { /* Force the creation from gNB Conf file */ - LOG_W(NR_RRC, "Adding %d DRBs, from gNB config file (not decided by 5GC\n", rrc->configuration.drbs); - drb_id = next_available_drb(ue, &ue->pduSession[i], GBR_FLOW); - } else { - drb_id = next_available_drb(ue, &ue->pduSession[i], NONGBR_FLOW); - } - break; - - default: - LOG_E(NR_RRC, "not supported 5qi %lu\n", ue->pduSession[i].param.qos[qos_flow_index].fiveQI); - ue->pduSession[i].status = PDU_SESSION_STATUS_FAILED; - continue; - } - drb_priority[drb_id - 1] = ue->pduSession[i].param.qos[qos_flow_index].allocation_retention_priority.priority_level; - if (drb_priority[drb_id - 1] < 0 || drb_priority[drb_id - 1] > NGAP_PRIORITY_LEVEL_NO_PRIORITY) { - LOG_E(NR_RRC, "invalid allocation_retention_priority.priority_level %ld set to _NO_PRIORITY\n", drb_priority[drb_id - 1]); - drb_priority[drb_id - 1] = NGAP_PRIORITY_LEVEL_NO_PRIORITY; - } - - if (drb_is_active(ue, drb_id)) { /* Non-GBR flow using the same DRB or a GBR flow with no available DRBs*/ - nb_drb_to_setup--; - } else { - generateDRB(ue, - drb_id, - &ue->pduSession[i], - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering); - NR_DRB_ToAddMod_t *DRB_config = generateDRB_ASN1(&ue->established_drbs[drb_id - 1]); - if (drb_id_to_setup_start == 0) - drb_id_to_setup_start = DRB_config->drb_Identity; - asn1cSeqAdd(&DRB_configList->list, DRB_config); - } - LOG_D(RRC, "DRB Priority %ld\n", drb_priority[drb_id]); // To supress warning for now - } - } - } - if (DRB_configList->list.count == 0) { - free(DRB_configList); - return NULL; - } - return DRB_configList; -} - static void freeDRBlist(NR_DRB_ToAddModList_t *list) { //ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); @@ -579,10 +512,12 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); OCTET_STRING_fromBuf(msg, (char *)ue_p->pduSession[i].param.nas_pdu.buffer, ue_p->pduSession[i].param.nas_pdu.length); - } - ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; - LOG_D(NR_RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n", i, ue_p->pduSession[i].status, "PDU_SESSION_STATUS_DONE"); + } + if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { + ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; + LOG_D(NR_RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n", i, ue_p->pduSession[i].status, "PDU_SESSION_STATUS_DONE"); + } } if (ue_p->nas_pdu.length) { @@ -659,34 +594,29 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(ue_p); ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = NULL; - NR_DedicatedNAS_Message_t *dedicatedNAS_Message = NULL; - dedicatedNAS_MessageList = CALLOC(1, sizeof(struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList)); + struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); - int nb_drb_to_setup = DRB_configList ? DRB_configList->list.count : 0; - for (int i=0; i < nb_drb_to_setup; i++) { - int j = ue_p->nb_of_pdusessions - 1; - AssertFatal(j >= 0, ""); - if (ue_p->pduSession[j].param.nas_pdu.buffer != NULL) { - dedicatedNAS_Message = CALLOC(1, sizeof(NR_DedicatedNAS_Message_t)); - memset(dedicatedNAS_Message, 0, sizeof(OCTET_STRING_t)); - OCTET_STRING_fromBuf(dedicatedNAS_Message, - (char *)ue_p->pduSession[j].param.nas_pdu.buffer, - ue_p->pduSession[j].param.nas_pdu.length); - ue_p->pduSession[j].status = PDU_SESSION_STATUS_DONE; - asn1cSeqAdd(&dedicatedNAS_MessageList->list, dedicatedNAS_Message); + for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { + if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { + asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); + OCTET_STRING_fromBuf(msg, + (char *)ue_p->pduSession[i].param.nas_pdu.buffer, + ue_p->pduSession[i].param.nas_pdu.length); + asn1cSeqAdd(&dedicatedNAS_MessageList->list, msg); - LOG_I(NR_RRC, "add NAS info with size %d (pdusession idx %d)\n", ue_p->pduSession[j].param.nas_pdu.length, j); - } else { - // TODO - LOG_E(NR_RRC, "no NAS info (pdusession idx %d)\n", j); + LOG_D(NR_RRC, "add NAS info with size %d (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.length, i); + ue_p->pduSession[i].xid = xid; + } + if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { + ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; } - - ue_p->pduSession[j].xid = xid; } - freeDRBlist(DRB_configList); + + if (ue_p->nas_pdu.length) { + asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); + OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buffer, ue_p->nas_pdu.length); + } /* If list is empty free the list and reset the address */ if (dedicatedNAS_MessageList->list.count == 0) { @@ -748,7 +678,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( //----------------------------------------------------------------------------- { gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(ue_p); int qos_flow_index = 0; uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue_p->xids[xid] = RRC_PDUSESSION_MODIFY; @@ -819,8 +748,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI); } - asn1cSeqAdd(&DRB_configList->list, DRB_config); - ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; ue_p->pduSession[i].xid = xid; @@ -839,19 +766,21 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( dedicatedNAS_MessageList = NULL; } + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); uint8_t buffer[RRC_BUF_SIZE]; int size = do_RRCReconfiguration(ue_p, buffer, RRC_BUF_SIZE, xid, NULL, - DRB_configList, + DRBs, NULL, NULL, NULL, dedicatedNAS_MessageList, NULL); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); + freeDRBlist(DRBs); /* Free all NAS PDUs */ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { @@ -2442,7 +2371,7 @@ rrc_gNB_generate_SecurityModeCommand( NR_IntegrityProtAlgorithm_t integrity_algorithm = (NR_IntegrityProtAlgorithm_t)ue_p->integrity_algorithm; size = do_NR_SecurityModeCommand(ctxt_pP, buffer, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id), ue_p->ciphering_algorithm, integrity_algorithm); LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Security Mode Command\n"); - LOG_I(NR_RRC, "UE %04x Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d)\n", ue_p->rnti, size); + LOG_I(NR_RRC, "UE %u Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d)\n", ue_p->rrc_ue_id, size); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 8bc76c570c..bc653a805c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -795,24 +795,35 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; pdu->teId = session->gtp_teid; memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target + + /* we assume for the moment one DRB per PDU session. Activate the bearer, + * and configure in RRC. */ + int drb_id = get_next_available_drb_id(UE); + drb_t *rrc_drb = generateDRB(UE, + drb_id, + pduSession, + rrc->configuration.enable_sdap, + rrc->security.do_drb_integrity, + rrc->security.do_drb_ciphering); + pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding for (int j=0; j < pdu->numDRB2Setup; j++) { DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; - drb->id = i + j + UE->nb_of_pdusessions; + drb->id = rrc_drb->drb_id; - drb->defaultDRB = true; + struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; + drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; + drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; - drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap); - drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap); + struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config; + drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL; + drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL; + drb->discardTimer = pdcp_config->discardTimer; + drb->reorderingTimer = pdcp_config->t_Reordering; - drb->pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_18; - drb->pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_18; - - drb->discardTimer = E1AP_DiscardTimer_infinity; - drb->reorderingTimer = E1AP_T_Reordering_ms100; - - drb->rLC_Mode = E1AP_RLC_Mode_rlc_am; + drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; drb->numCellGroups = 1; // assume one cell group associated with a DRB diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index efff9f2d8a..9c8f26e3a5 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -37,62 +37,71 @@ rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create) return ue->pduSession + j; } -void generateDRB(gNB_RRC_UE_t *ue, - uint8_t drb_id, - rrc_pdu_session_param_t *pduSession, - bool enable_sdap, - int do_drb_integrity, - int do_drb_ciphering) +drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) { - int i; - int qos_flow_index; + DevAssert(drb_id > 0 && drb_id < 32); + DevAssert(ue != NULL); + + return &ue->established_drbs[drb_id - 1]; +} + +drb_t *generateDRB(gNB_RRC_UE_t *ue, + uint8_t drb_id, + const rrc_pdu_session_param_t *pduSession, + bool enable_sdap, + int do_drb_integrity, + int do_drb_ciphering) +{ + DevAssert(ue != NULL); + + LOG_I(NR_RRC, "UE %d: configure DRB ID %d for PDU session ID %d\n", ue->rrc_ue_id, drb_id, pduSession->param.pdusession_id); + drb_t *est_drb = &ue->established_drbs[drb_id - 1]; - if (est_drb->status == DRB_INACTIVE) { - /* DRB Management */ - est_drb->drb_id = drb_id; - est_drb->reestablishPDCP = -1; - est_drb->recoverPDCP = -1; - for (i = 0; i < MAX_DRBS_PER_UE; i++) { - if ((est_drb->cnAssociation.sdap_config.pdusession_id == 0 - || est_drb->cnAssociation.sdap_config.pdusession_id == pduSession->param.pdusession_id) - && est_drb->defaultDRBid == 0) { - 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; - est_drb->cnAssociation.sdap_config.pdusession_id = pduSession->param.pdusession_id; - if (enable_sdap) { - est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present; - est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present; - } else { - est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; - est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; - } - for (qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) { - est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi; - if (pduSession->param.qos[qos_flow_index].fiveQI > 5) - est_drb->status = DRB_ACTIVE_NONGBR; - else - est_drb->status = DRB_ACTIVE; - } - /* PDCP Configuration */ - est_drb->pdcp_config.discardTimer = NR_PDCP_Config__drb__discardTimer_infinity; - est_drb->pdcp_config.pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len18bits; - est_drb->pdcp_config.pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len18bits; - est_drb->pdcp_config.t_Reordering = NR_PDCP_Config__t_Reordering_ms100; - est_drb->pdcp_config.headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; - est_drb->pdcp_config.headerCompression.NotUsed = 0; - if (do_drb_integrity) - est_drb->pdcp_config.integrityProtection = NR_PDCP_Config__drb__integrityProtection_enabled; - else - est_drb->pdcp_config.integrityProtection = 1; - if (do_drb_ciphering) - est_drb->pdcp_config.ext1.cipheringDisabled = 1; - else - est_drb->pdcp_config.ext1.cipheringDisabled = NR_PDCP_Config__ext1__cipheringDisabled_true; + DevAssert(est_drb->status == DRB_INACTIVE); + + 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; + est_drb->cnAssociation.sdap_config.pdusession_id = pduSession->param.pdusession_id; + if (enable_sdap) { + est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present; + est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present; + } else { + est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; + est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; } + for (int qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) { + est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi; + if (pduSession->param.qos[qos_flow_index].fiveQI > 5) + est_drb->status = DRB_ACTIVE_NONGBR; + else + est_drb->status = DRB_ACTIVE; + } + /* PDCP Configuration */ + est_drb->pdcp_config.discardTimer = NR_PDCP_Config__drb__discardTimer_infinity; + est_drb->pdcp_config.pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len18bits; + est_drb->pdcp_config.pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len18bits; + est_drb->pdcp_config.t_Reordering = NR_PDCP_Config__t_Reordering_ms100; + est_drb->pdcp_config.headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; + est_drb->pdcp_config.headerCompression.NotUsed = 0; + if (do_drb_integrity) + est_drb->pdcp_config.integrityProtection = NR_PDCP_Config__drb__integrityProtection_enabled; + else + est_drb->pdcp_config.integrityProtection = 1; + if (do_drb_ciphering) + est_drb->pdcp_config.ext1.cipheringDisabled = 1; + else + est_drb->pdcp_config.ext1.cipheringDisabled = NR_PDCP_Config__ext1__cipheringDisabled_true; + + drb_t *rrc_drb = get_drb(ue, drb_id); + DevAssert(rrc_drb == est_drb); /* to double check that we create the same which we would retrieve */ + return rrc_drb; } NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1) @@ -143,17 +152,9 @@ NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1) return DRB_config; } -uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession, bool is_gbr) +uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue) { - uint8_t drb_id; - - if (0 /*!is_gbr*/) { /* Find if Non-GBR DRB exists in the same PDU Session */ - for (drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) - if (pdusession->param.used_drbs[drb_id] == DRB_ACTIVE_NONGBR) - return drb_id + 1; - } - /* GBR Flow or a Non-GBR DRB does not exist in the same PDU Session, find an available DRB */ - for (drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) + for (uint8_t drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) if (ue->established_drbs[drb_id].status == DRB_INACTIVE) return drb_id + 1; /* From this point, we need to handle the case that all DRBs are already used by the UE. */ @@ -163,6 +164,8 @@ uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) { - DevAssert(drb_id > 0); - return ue->established_drbs[drb_id - 1].status == DRB_ACTIVE; + drb_t *drb = get_drb(ue, drb_id); + if (drb == NULL) + return DRB_INACTIVE; + return drb->status != DRB_INACTIVE; } diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index aff6e75ea6..ff348139de 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -39,23 +39,33 @@ /// @param drb_t drb_asn1 /// @return Returns the ASN1 DRB-ToAddMod structs. NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1); -/// @brief Creates and stores a DRB in the gNB_RRC_UE_t struct, it doesn't create the actual entity, -/// to create the actual entity use the generateDRB_ASN1. + +/// @brief retrieve the data structure representing DRB with ID drb_id of UE ue +drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id); + +/// @brief Creates and stores a DRB in the gNB_RRC_UE_t struct /// @param ue The gNB_RRC_UE_t struct that holds information for the UEs /// @param drb_id The Data Radio Bearer Identity to be created for the established DRB. /// @param pduSession The PDU Session that the DRB is created for. /// @param enable_sdap If true the SDAP header will be added to the packet, else it will not add or search for SDAP header. /// @param do_drb_integrity /// @param do_drb_ciphering -void generateDRB(gNB_RRC_UE_t *ue, - uint8_t drb_id, - rrc_pdu_session_param_t *pduSession, - bool enable_sdap, - int do_drb_integrity, - int do_drb_ciphering); -uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession, bool is_gbr); +/// @return returns a pointer to the generated DRB structure +drb_t *generateDRB(gNB_RRC_UE_t *ue, + uint8_t drb_id, + const rrc_pdu_session_param_t *pduSession, + bool enable_sdap, + int do_drb_integrity, + int do_drb_ciphering); + +/// @brief return the next available (inactive) DRB ID of UE ue +uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue); + +/// @brief check if DRB with ID drb_id of UE ue is active bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id); +/// @brief retrieve PDU session of UE ue with ID id, optionally creating it if +/// create is true rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create); #endif From 59b69e240a9f9e9089317ca20fcacc83fea2cc09 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Jan 2024 15:09:29 +0100 Subject: [PATCH 38/47] correctly free NAS pdus: avoid possible double-frees --- openair2/RRC/NR/rrc_gNB.c | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 377e15bbab..87eca909a9 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -121,6 +121,14 @@ mui_t rrc_gNB_mui = 0; ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// +static void clear_nas_pdu(ngap_pdu_t *pdu) +{ + DevAssert(pdu != NULL); + free(pdu->buffer); // does nothing if NULL + pdu->buffer = NULL; + pdu->length = 0; +} + static void freeDRBlist(NR_DRB_ToAddModList_t *list) { //ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); @@ -563,18 +571,13 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, ue_p->masterCellGroup); } - // suspicious if it is always malloced before ? - free(ue_p->nas_pdu.buffer); + clear_nas_pdu(&ue_p->nas_pdu); LOG_DUMPMSG(NR_RRC, DEBUG_RRC,(char *)buffer, size, "[MSG] RRC Reconfiguration\n"); /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { - free(ue_p->pduSession[i].param.nas_pdu.buffer); - ue_p->pduSession[i].param.nas_pdu.buffer = NULL; - } - } + for (int i = 0; i < ue_p->nb_of_pdusessions; i++) + clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate NR_RRCReconfiguration (bytes %d, UE id %x)\n", ctxt_pP->module_id, @@ -625,13 +628,8 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c } /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { - /* Free the NAS PDU buffer and invalidate it */ - free(ue_p->pduSession[i].param.nas_pdu.buffer); - ue_p->pduSession[i].param.nas_pdu.buffer = NULL; - } - } + for (int i = 0; i < ue_p->nb_of_pdusessions; i++) + clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); NR_CellGroupConfig_t *cellGroupConfig = ue_p->masterCellGroup; @@ -755,8 +753,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( asn1cSequenceAdd(dedicatedNAS_MessageList->list,NR_DedicatedNAS_Message_t, dedicatedNAS_Message); OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)ue_p->pduSession[i].param.nas_pdu.buffer, ue_p->pduSession[i].param.nas_pdu.length); LOG_I(NR_RRC, "add NAS info with size %d (pdusession id %d)\n", ue_p->pduSession[i].param.nas_pdu.length, ue_p->pduSession[i].param.pdusession_id); - } else { - LOG_W(NR_RRC, "no NAS info (pdusession id %d)\n", ue_p->pduSession[i].param.pdusession_id); } } @@ -783,13 +779,8 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( freeDRBlist(DRBs); /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { - /* Free the NAS PDU buffer and invalidate it */ - free(ue_p->pduSession[i].param.nas_pdu.buffer); - ue_p->pduSession[i].param.nas_pdu.buffer = NULL; - } - } + for (int i = 0; i < ue_p->nb_of_pdusessions; i++) + clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCReconfiguration (bytes %d, UE RNTI %x)\n", ctxt_pP->module_id, ctxt_pP->frame, size, ue_p->rnti); LOG_D(NR_RRC, From c818e9b5fed9edd779db50fa507af200df54d6ad Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 08:27:54 +0100 Subject: [PATCH 39/47] F1 UE Ctxt modif response: look up PDU sessions --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 1 + openair2/RRC/NR/rrc_gNB.c | 86 +++++++++++++++------ openair2/RRC/NR/rrc_gNB_radio_bearers.c | 11 +++ openair2/RRC/NR/rrc_gNB_radio_bearers.h | 3 + 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index ec4dc7d167..0f1d130cb5 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -240,6 +240,7 @@ void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) instance_t f1inst = get_f1_gtp_instance(); for (int i=0; i < req->numPDUSessionsMod; i++) { + DevAssert(req->pduSessionMod[i].sessionId > 0); LOG_I(E1AP, "UE %d: updating PDU session ID %ld (%ld bearers)\n", req->gNB_cu_up_ue_id, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 87eca909a9..1b0e5c1e1b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1671,6 +1671,67 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC rrc_remove_nsa_user(rrc, m->rnti); } +/* \brief fill E1 bearer modification's DRB from F1 DRB + * \param drb_e1 pointer to a DRB inside an E1 bearer modification message + * \param drb_f1 pointer to a DRB inside an F1 UE Ctxt modification Response */ +static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) +{ + drb_e1->id = drb_f1->drb_id; + drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length; + drb_e1->DlUpParamList[0].tlAddress = drb_f1->up_dl_tnl[0].tl_address; + drb_e1->DlUpParamList[0].teId = drb_f1->up_dl_tnl[0].teid; +} + +/* \brief find existing PDU session inside E1AP Bearer Modif message, or + * point to new one. + * \param bearer_modif E1AP Bearer Modification Message + * \param pdu_id PDU session ID + * \return pointer to existing PDU session, or to new/unused one. */ +static pdu_session_to_setup_t *find_or_next_pdu_session(e1ap_bearer_setup_req_t *bearer_modif, int pdu_id) +{ + for (int i = 0; i < bearer_modif->numPDUSessionsMod; ++i) { + if (bearer_modif->pduSessionMod[i].sessionId == pdu_id) + return &bearer_modif->pduSessionMod[i]; + } + /* E1AP Bearer Modification has no PDU session to modify with that ID, create + * new entry */ + DevAssert(bearer_modif->numPDUSessionsMod < E1AP_MAX_NUM_PDU_SESSIONS - 1); + bearer_modif->numPDUSessionsMod += 1; + return &bearer_modif->pduSessionMod[bearer_modif->numPDUSessionsMod - 1]; +} + +/* \brief use list of DRBs and send the corresponding bearer update message via + * E1 to the CU of this UE */ +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 + e1ap_bearer_setup_req_t req = { + .gNB_cu_cp_ue_id = UE->rrc_ue_id, + .gNB_cu_up_ue_id = UE->rrc_ue_id, + }; + + for (int i = 0; i < n; i++) { + const f1ap_drb_to_be_setup_t *drb_f1 = &drbs[i]; + rrc_pdu_session_param_t *pdu_ue = find_pduSession_from_drbId(UE, drb_f1->drb_id); + if (pdu_ue == NULL) { + LOG_E(RRC, "UE %d: UE Context Modif Response: no PDU session for DRB ID %ld\n", UE->rrc_ue_id, drb_f1->drb_id); + continue; + } + pdu_session_to_setup_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); + 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]; + fill_e1_bearer_modif(drb_e1, drb_f1); + pdu_e1->numDRB2Modify += 1; + } + DevAssert(req.numPDUSessionsMod > 0); + DevAssert(req.numPDUSessions == 0); + + // send the E1 bearer modification request message to update F1-U tunnel info + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); + rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); +} + static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance_t instance) { f1ap_ue_context_setup_t *resp = &F1AP_UE_CONTEXT_SETUP_RESP(msg_p); @@ -1764,30 +1825,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) { - e1ap_bearer_setup_req_t req = {0}; - // TODO: bug: we receive the DRBs, but we don't associate to a PDU session - // -> we are not sure which PDU session this is, and fill "all" - req.numPDUSessionsMod = UE->nb_of_pdusessions; - req.gNB_cu_cp_ue_id = UE->rrc_ue_id; - req.gNB_cu_up_ue_id = UE->rrc_ue_id; - for (int i = 0; i < req.numPDUSessionsMod; i++) { - req.pduSessionMod[i].sessionId = UE->pduSession[i].param.pdusession_id; - req.pduSessionMod[i].numDRB2Modify = resp->drbs_to_be_setup_length; - for (int j = 0; j < resp->drbs_to_be_setup_length; j++) { - f1ap_drb_to_be_setup_t *drb_f1 = resp->drbs_to_be_setup + j; - DRB_nGRAN_to_setup_t *drb_e1 = req.pduSessionMod[i].DRBnGRanModList + j; - - drb_e1->id = drb_f1->drb_id; - drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length; - drb_e1->DlUpParamList[0].tlAddress = drb_f1->up_dl_tnl[0].tl_address; - drb_e1->DlUpParamList[0].teId = drb_f1->up_dl_tnl[0].teid; - } - } - - // send the F1 response message up to update F1-U tunnel info - // it seems the rrc transaction id (xid) is not needed here - sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); - rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); + e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); } if (resp->du_to_cu_rrc_information != NULL && resp->du_to_cu_rrc_information->cellGroupConfig != NULL) { diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 9c8f26e3a5..303c5ae20d 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -37,6 +37,17 @@ rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create) return ue->pduSession + j; } +rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id) +{ + const drb_t *drb = &ue->established_drbs[drb_id - 1]; + if (drb->status == DRB_INACTIVE) { + LOG_E(NR_RRC, "UE %d: DRB %d inactive\n", ue->rrc_ue_id, drb_id); + return NULL; + } + int id = drb->cnAssociation.sdap_config.pdusession_id; + return find_pduSession(ue, id, false); +} + drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) { DevAssert(drb_id > 0 && drb_id < 32); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index ff348139de..d29f3635ab 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -68,4 +68,7 @@ bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id); /// create is true rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create); +/// @brief get PDU session of UE ue through the DRB drb_id +rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id); + #endif From 6642b467e1cb69f10cbdc6e55c8b9d2ccf36cff4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 26 Jan 2024 12:17:02 +0100 Subject: [PATCH 40/47] Implement PDU session estab through NGAP Initial UE Context Setup This commit allows the gNB to handle PDU sessions that the core requests to setup during the NGAP Initial UE Context Setup. Previously, we only managed them as part of PDU Session Resource Setup Request. The RRC will, depending on whether a PDU session is in the NGAP Initial UE Context Setup, either directly trigger the Security Command, or first do a bearer setup at the CU-UP. Some asserts have been lifted, as now the PDU sessions might be present before the RRC Connection is fully established. Implement the correct forwarding of the bearers in an F1 UE Context Setup Request message. This solves bug #672. --- .../LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c | 8 +- openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c | 8 +- openair2/RRC/NR/mac_rrc_dl_f1ap.c | 16 +- openair2/RRC/NR/nr_rrc_proto.h | 4 +- openair2/RRC/NR/rrc_gNB.c | 39 ++- openair2/RRC/NR/rrc_gNB_NGAP.c | 257 ++++++++---------- 6 files changed, 182 insertions(+), 150 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index b9ca19300a..bcf7c26ae6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -69,7 +69,6 @@ static void f1_setup_request_direct(const f1ap_setup_req_t *req) static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) { DevAssert(req->drbs_to_be_setup_length == resp->drbs_to_be_setup_length); - AssertFatal(req->drbs_to_be_setup_length == 0, "not implemented\n"); (void) req; /* we don't need the request -- it is to set up GTP in F1 case */ MessageDef *msg = itti_alloc_new_message (TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_SETUP_RESP); @@ -85,6 +84,13 @@ static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; } + if (resp->drbs_to_be_setup_length > 0) { + DevAssert(resp->drbs_to_be_setup != NULL); + f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); + for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) + f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; + } f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 8e0a04cac8..fea829f61e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -103,7 +103,6 @@ static void f1_setup_request_f1ap(const f1ap_setup_req_t *req) static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) { DevAssert(req->drbs_to_be_setup_length == resp->drbs_to_be_setup_length); - AssertFatal(req->drbs_to_be_setup_length == 0, "not implmented\n"); DevAssert(req->srbs_to_be_setup_length == resp->srbs_to_be_setup_length); MessageDef *msg = itti_alloc_new_message (TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_SETUP_RESP); @@ -118,6 +117,13 @@ static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, c for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; } + if (resp->drbs_to_be_setup_length > 0) { + DevAssert(resp->drbs_to_be_setup != NULL); + f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); + for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) + f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; + } f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index 891d5d94f1..e501dde45b 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -51,8 +51,20 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c f1ap_ue_context_setup_t *f1ap_msg = &F1AP_UE_CONTEXT_SETUP_REQ(msg); *f1ap_msg = *req; AssertFatal(req->cu_to_du_rrc_information == NULL, "cu_to_du_rrc_information not supported yet\n"); - AssertFatal(req->drbs_to_be_setup == NULL, "drbs_to_be_setup not supported yet\n"); - AssertFatal(req->srbs_to_be_setup == NULL, "drbs_to_be_setup not supported yet\n"); + if (req->drbs_to_be_setup_length > 0) { + int n = req->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup_length = n; + f1ap_msg->drbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->drbs_to_be_setup)); + AssertFatal(f1ap_msg->drbs_to_be_setup != NULL, "out of memory\n"); + memcpy(f1ap_msg->drbs_to_be_setup, req->drbs_to_be_setup, n * sizeof(*f1ap_msg->drbs_to_be_setup)); + } + if (req->srbs_to_be_setup_length > 0) { + int n = req->srbs_to_be_setup_length; + f1ap_msg->srbs_to_be_setup_length = n; + f1ap_msg->srbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->srbs_to_be_setup)); + AssertFatal(f1ap_msg->srbs_to_be_setup != NULL, "out of memory\n"); + memcpy(f1ap_msg->srbs_to_be_setup, req->srbs_to_be_setup, n * sizeof(*f1ap_msg->srbs_to_be_setup)); + } if (req->rrc_container_length > 0) { f1ap_msg->rrc_container = calloc(req->rrc_container_length, sizeof(*f1ap_msg->rrc_container)); AssertFatal(f1ap_msg->rrc_container != NULL, "out of memory\n"); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 7c2374acfa..e034005ceb 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -81,7 +81,9 @@ int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo, x2 void rrc_gNB_generate_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *const ue_context_pP + rrc_gNB_ue_context_t *const ue_context_pP, + int n_drbs, + const f1ap_drb_to_be_setup_t *drbs ); unsigned int rrc_gNB_get_next_transaction_identifier(module_id_t gnb_mod_idP); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1b0e5c1e1b..b054b2c58b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -509,7 +509,6 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co { gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - AssertFatal(ue_p->nb_of_pdusessions == 0, "logic bug: PDU sessions present before RRC Connection established\n"); uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue_p->xids[xid] = RRC_DEFAULT_RECONF; @@ -551,14 +550,16 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co uint32_t ssb_arfcn = get_ssb_arfcn(cell_info, du->mib, du->sib1); measconfig = get_defaultMeasConfig(ssb_arfcn, band, scs); } + NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); uint8_t buffer[RRC_BUF_SIZE] = {0}; int size = do_RRCReconfiguration(ue_p, buffer, RRC_BUF_SIZE, xid, - NULL, //*SRB_configList2, - NULL, //*DRB_configList, + SRBs, + DRBs, NULL, NULL, measconfig, @@ -566,6 +567,8 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co ue_p->masterCellGroup); AssertFatal(size > 0, "cannot encode RRCReconfiguration in %s()\n", __func__); free_defaultMeasConfig(measconfig); + freeSRBlist(SRBs); + freeDRBlist(DRBs); if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, ue_p->masterCellGroup); @@ -1759,6 +1762,11 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); + if (resp->drbs_to_be_setup_length > 0) { + AssertFatal(resp->srbs_to_be_setup_length > 0 && resp->srbs_to_be_setup[0].srb_id == 2, "logic bug: we set up DRBs, so need to have both SRB1&SRB2\n"); + e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); + } + /* at this point, we don't have to do anything: the UE context setup request * includes the Security Command, whose response will trigger the following * messages (UE capability, to be specific) */ @@ -2006,7 +2014,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp /* Instruction towards the DU for SRB2 configuration */ int nb_srb = 0; - f1ap_srb_to_be_setup_t srbs[1]; + f1ap_srb_to_be_setup_t srbs[1] = {0}; if (UE->Srb[2].Active == 0) { activate_srb(UE, 2); nb_srb = 1; @@ -2017,7 +2025,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp if (!UE->as_security_active) { /* no AS security active, need to send UE context setup req with security * command (and the bearers) */ - AssertFatal(false, "not implemented yet\n"); + protocol_ctxt_t ctxt = {.rntiMaybeUEid = UE->rrc_ue_id}; + rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p, nb_drb, drbs); return; } @@ -2387,7 +2396,9 @@ static void rrc_deliver_ue_ctxt_setup_req(void *deliver_pdu_data, ue_id_t ue_id, void rrc_gNB_generate_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *const ue_context_pP + rrc_gNB_ue_context_t *const ue_context_pP, + int n_drbs, + const f1ap_drb_to_be_setup_t *drbs ) //----------------------------------------------------------------------------- { @@ -2413,6 +2424,16 @@ rrc_gNB_generate_SecurityModeCommand( cu2du.uE_CapabilityRAT_ContainerList_length = ue_p->ue_cap_buffer.len; } + int nb_srb = 0; + f1ap_srb_to_be_setup_t srb_buf[1] = {0}; + f1ap_srb_to_be_setup_t *srbs = 0; + if (n_drbs > 0) { + nb_srb = 1; + srb_buf[0].srb_id = 2; + srb_buf[0].lcid = 2; + srbs = srb_buf; + } + /* 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); @@ -2424,8 +2445,10 @@ rrc_gNB_generate_SecurityModeCommand( .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], .nr_cellid = rrc->nr_cellid, .servCellId = 0, /* TODO: correct value? */ - .srbs_to_be_setup = 0, /* no new SRBs */ - .drbs_to_be_setup = 0, /* no new DRBs */ + .srbs_to_be_setup_length = nb_srb, + .srbs_to_be_setup = srbs, + .drbs_to_be_setup_length = n_drbs, + .drbs_to_be_setup = (f1ap_drb_to_be_setup_t *) drbs, .cu_to_du_rrc_information = cu2du_p, }; deliver_ue_ctxt_setup_data_t data = {.rrc = rrc, .setup_req = &ue_context_setup_req, .assoc_id = ue_data.du_assoc_id }; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index bc653a805c..e3e83610f2 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -362,6 +362,111 @@ static int decodePDUSessionResourceSetup(pdusession_t *session) return 0; } +static void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession_t *sessions, uint64_t ueAggMaxBitRateDownlink) +{ + e1ap_bearer_setup_req_t bearer_req = {0}; + + e1ap_nssai_t cuup_nssai = {0}; + for (int i = 0; i < n; i++) { + rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true); + pdusession_t *session = &pduSession->param; + session->pdusession_id = sessions[i].pdusession_id; + LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); + session->pdu_session_type = sessions[i].pdu_session_type; + session->nas_pdu = sessions[i].nas_pdu; + session->pdusessionTransfer = sessions[i].pdusessionTransfer; + session->nssai = sessions[i].nssai; + decodePDUSessionResourceSetup(session); + bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; + bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; + bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; + nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); + nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); + bearer_req.ueDlAggMaxBitRate = ueAggMaxBitRateDownlink; + pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; + bearer_req.numPDUSessions++; + pdu->sessionId = session->pdusession_id; + pdu->nssai = sessions[i].nssai; + if (cuup_nssai.sst == 0) + cuup_nssai = pdu->nssai; /* for CU-UP selection below */ + + pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; + + pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; + pdu->teId = session->gtp_teid; + memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target + + /* we assume for the moment one DRB per PDU session. Activate the bearer, + * and configure in RRC. */ + int drb_id = get_next_available_drb_id(UE); + drb_t *rrc_drb = generateDRB(UE, + drb_id, + pduSession, + rrc->configuration.enable_sdap, + rrc->security.do_drb_integrity, + rrc->security.do_drb_ciphering); + + pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding + for (int j=0; j < pdu->numDRB2Setup; j++) { + DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; + + drb->id = rrc_drb->drb_id; + + struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; + drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; + drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; + + struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config; + drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL; + drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL; + drb->discardTimer = pdcp_config->discardTimer; + drb->reorderingTimer = pdcp_config->t_Reordering; + + drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; + + drb->numCellGroups = 1; // assume one cell group associated with a DRB + + for (int k=0; k < drb->numCellGroups; k++) { + cell_group_t *cellGroup = drb->cellGroupList + k; + cellGroup->id = 0; // MCG + } + + drb->numQosFlow2Setup = session->nb_qos; + for (int k=0; k < drb->numQosFlow2Setup; k++) { + qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; + pdusession_level_qos_parameter_t *qos_session = session->qos + k; + + qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; + qos_flow->qfi = qos_session->qfi; + qos_char->qos_type = qos_session->fiveQI_type; + if (qos_char->qos_type == dynamic) { + qos_char->dynamic.fiveqi = qos_session->fiveQI; + qos_char->dynamic.qos_priority_level = qos_session->qos_priority; + } else { + qos_char->non_dynamic.fiveqi = qos_session->fiveQI; + qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority; + } + + ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; + ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority; + rent_priority->priority_level = rent_priority_in->priority_level; + rent_priority->preemption_capability = rent_priority_in->pre_emp_capability; + rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability; + } + } + } + int xid = rrc_gNB_get_next_transaction_identifier(0); + UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; + /* Limitation: we assume one fixed CU-UP per UE. We base the selection on + * NSSAI, but the UE might have multiple PDU sessions with differing slices, + * in which we might need to select different CU-UPs. In this case, we would + * actually need to group the E1 bearer context setup for the different + * CU-UPs, and send them to the different CU-UPs. */ + sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd); + rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); +} + //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t instance) //------------------------------------------------------------------------------ @@ -384,40 +489,6 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t } PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0); UE->amf_ue_ngap_id = req->amf_ue_ngap_id; - uint8_t nb_pdusessions_tosetup = req->nb_of_pdusessions; - if (nb_pdusessions_tosetup) { - AssertFatal(false, "PDU sessions in Initial context setup request not handled by E1 yet\n"); - /* this code should pass by E1: commenting here for future reference, but - * already handled in E1 for the "normal case" of a separate request for - * PDU session setup. - gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0}; - for (int i = 0; i < nb_pdusessions_tosetup; i++) { - UE->nb_of_pdusessions++; - if(UE->pduSession[i].status >= PDU_SESSION_STATUS_DONE) - continue; - UE->pduSession[i].status = PDU_SESSION_STATUS_NEW; - UE->pduSession[i].param = req->pdusession_param[i]; - create_tunnel_req.num_tunnels++; - create_tunnel_req.pdusession_id[i] = req->pdusession_param[i].pdusession_id; - create_tunnel_req.outgoing_teid[i] = req->pdusession_param[i].gtp_teid; - // To be developped: hardcoded first flow - create_tunnel_req.outgoing_qfi[i] = req->pdusession_param[i].qos[0].qfi; - create_tunnel_req.dst_addr[i].length = req->pdusession_param[i].upf_addr.length; - memcpy(create_tunnel_req.dst_addr[i].buffer, req->pdusession_param[i].upf_addr.buffer, sizeof(create_tunnel_req.dst_addr[i].buffer)); - LOG_I(NR_RRC, "PDUSESSION SETUP: local index %d teid %u, pdusession id %d \n", i, create_tunnel_req.outgoing_teid[i], create_tunnel_req.pdusession_id[i]); - } - create_tunnel_req.ue_id = UE->rrc_ue_id; - gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp = {0}; - int ret = gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, &create_tunnel_resp, nr_pdcp_data_req_drb, sdap_data_req); - if (ret != 0) { - LOG_E(NR_RRC, "rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ : gtpv1u_create_ngu_tunnel failed,start to release UE %x\n", UE->rnti); - AssertFatal(false, "release timer not implemented\n"); - return (0); - } - - nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0); - */ - } /* NAS PDU */ // this is malloced pointers, we pass it for later free() @@ -430,7 +501,19 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t /* configure only integrity, ciphering comes after receiving SecurityModeComplete */ nr_rrc_pdcp_config_security(&ctxt, ue_context_p, 0); - rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p); + uint8_t nb_pdusessions_tosetup = req->nb_of_pdusessions; + /* if there are PDU sessions to setup, first send them to the CU-UP, then + * send the UE Context setup with Security commend. Else go to the security + * command directly. */ + if (nb_pdusessions_tosetup > 0) { + trigger_bearer_setup(RC.nrrrc[instance], + UE, + req->nb_of_pdusessions, + req->pdusession_param, + /*req->ueAggMaxBitRateDownlink*/ 0); + } else { + rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p, 0, NULL); + } return 0; } @@ -762,109 +845,9 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return ; } - UE->rrc_ue_id = msg->gNB_ue_ngap_id; + AssertFatal(UE->rrc_ue_id == msg->gNB_ue_ngap_id, "logic bug\n"); UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; - e1ap_bearer_setup_req_t bearer_req = {0}; - - - e1ap_nssai_t cuup_nssai = {0}; - for (int i = 0; i < msg->nb_pdusessions_tosetup; i++) { - rrc_pdu_session_param_t *pduSession = find_pduSession(UE, msg->pdusession_setup_params[i].pdusession_id, true); - pdusession_t *session = &pduSession->param; - session->pdusession_id = msg->pdusession_setup_params[i].pdusession_id; - LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); - session->pdu_session_type = msg->pdusession_setup_params[i].pdu_session_type; - session->nas_pdu = msg->pdusession_setup_params[i].nas_pdu; - session->pdusessionTransfer = msg->pdusession_setup_params[i].pdusessionTransfer; - session->nssai = msg->pdusession_setup_params[i].nssai; - decodePDUSessionResourceSetup(session); - bearer_req.gNB_cu_cp_ue_id = msg->gNB_ue_ngap_id; - bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; - bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; - nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); - nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); - bearer_req.ueDlAggMaxBitRate = msg->ueAggMaxBitRateDownlink; - pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; - bearer_req.numPDUSessions++; - pdu->sessionId = session->pdusession_id; - pdu->nssai = msg->pdusession_setup_params[i].nssai; - if (cuup_nssai.sst == 0) - cuup_nssai = pdu->nssai; /* for CU-UP selection below */ - pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; - - pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; - pdu->teId = session->gtp_teid; - memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target - - /* we assume for the moment one DRB per PDU session. Activate the bearer, - * and configure in RRC. */ - int drb_id = get_next_available_drb_id(UE); - drb_t *rrc_drb = generateDRB(UE, - drb_id, - pduSession, - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering); - - pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding - for (int j=0; j < pdu->numDRB2Setup; j++) { - DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; - - drb->id = rrc_drb->drb_id; - - struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; - drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; - drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; - drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; - - struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config; - drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL; - drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL; - drb->discardTimer = pdcp_config->discardTimer; - drb->reorderingTimer = pdcp_config->t_Reordering; - - drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; - - drb->numCellGroups = 1; // assume one cell group associated with a DRB - - for (int k=0; k < drb->numCellGroups; k++) { - cell_group_t *cellGroup = drb->cellGroupList + k; - cellGroup->id = 0; // MCG - } - - drb->numQosFlow2Setup = session->nb_qos; - for (int k=0; k < drb->numQosFlow2Setup; k++) { - qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; - pdusession_level_qos_parameter_t *qos_session = session->qos + k; - - qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; - qos_flow->qfi = qos_session->qfi; - qos_char->qos_type = qos_session->fiveQI_type; - if (qos_char->qos_type == dynamic) { - qos_char->dynamic.fiveqi = qos_session->fiveQI; - qos_char->dynamic.qos_priority_level = qos_session->qos_priority; - } else { - qos_char->non_dynamic.fiveqi = qos_session->fiveQI; - qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority; - } - - ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; - ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority; - rent_priority->priority_level = rent_priority_in->priority_level; - rent_priority->preemption_capability = rent_priority_in->pre_emp_capability; - rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability; - } - } - } - int xid = rrc_gNB_get_next_transaction_identifier(instance); - UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; - /* Limitation: we assume one fixed CU-UP per UE. We base the selection on - * NSSAI, but the UE might have multiple PDU sessions with differing slices, - * in which we might need to select different CU-UPs. In this case, we would - * actually need to group the E1 bearer context setup for the different - * CU-UPs, and send them to the different CU-UPs. */ - sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd); - rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); + trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink); return; } From c643abd83e4922505b43df51244074f50c75e0ad Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 31 Jan 2024 16:20:00 +0100 Subject: [PATCH 41/47] DRB handling: handle E1AP default DRB logic properly --- openair2/E1AP/e1ap.c | 4 ++-- openair2/RRC/NR/rrc_gNB_NGAP.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 79581698d9..64ded829ed 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -665,7 +665,7 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bear asn1cSequenceAdd(ieC6_1->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1); ieC6_1_1->dRB_ID = j->id; - ieC6_1_1->sDAP_Configuration.defaultDRB = j->defaultDRB; + ieC6_1_1->sDAP_Configuration.defaultDRB = j->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; ieC6_1_1->sDAP_Configuration.sDAP_Header_UL = j->sDAP_Header_UL; ieC6_1_1->sDAP_Configuration.sDAP_Header_DL = j->sDAP_Header_DL; @@ -971,7 +971,7 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_beare drb->id = drb2Setup->dRB_ID; - drb->defaultDRB = drb2Setup->sDAP_Configuration.defaultDRB; + drb->defaultDRB = drb2Setup->sDAP_Configuration.defaultDRB == E1AP_DefaultDRB_true; drb->sDAP_Header_UL = drb2Setup->sDAP_Configuration.sDAP_Header_UL; drb->sDAP_Header_DL = drb2Setup->sDAP_Configuration.sDAP_Header_DL; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index e3e83610f2..b74a9a759c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -413,7 +413,7 @@ static void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdu drb->id = rrc_drb->drb_id; struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; - drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + drb->defaultDRB = sdap_config->defaultDRB; drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; From 62200cdee5d22d7edc4454198c92ecd27ddce59b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 09:30:27 +0100 Subject: [PATCH 42/47] RRC transactions: mark "no action" --- openair2/RRC/NR/nr_rrc_defs.h | 1 + openair2/RRC/NR/rrc_gNB.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 1db349f003..a0e7fa2b03 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -224,6 +224,7 @@ typedef struct drb_s { } drb_t; typedef enum { + RRC_ACTION_NONE, /* no transaction ongoing */ RRC_SETUP, RRC_SETUP_FOR_REESTABLISHMENT, RRC_REESTABLISH, diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b054b2c58b..7cd37f08ba 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1434,11 +1434,16 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ case RRC_DEDICATED_RECONF: /* do nothing */ break; + case RRC_ACTION_NONE: + LOG_E(RRC, "UE %d: Received RRC Reconfiguration Complete with xid %d while no transaction is ongoing\n", UE->rrc_ue_id, xid); + successful_reconfig = false; + break; default: - LOG_E(RRC, "Received unexpected transaction type %d for xid %d\n", UE->xids[xid], xid); + LOG_E(RRC, "UE %d: Received unexpected transaction type %d for xid %d\n", UE->rrc_ue_id, UE->xids[xid], xid); successful_reconfig = false; break; } + UE->xids[xid] = RRC_ACTION_NONE; gNB_RRC_INST *rrc = RC.nrrrc[0]; f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); From 8302a060fa09ef19fc99fea360aa737b6b6d7b9b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 09:30:44 +0100 Subject: [PATCH 43/47] RRC transactions: mark UE Capability transaction --- openair2/RRC/NR/nr_rrc_defs.h | 3 ++- openair2/RRC/NR/rrc_gNB.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index a0e7fa2b03..1aed82e4a0 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -233,7 +233,8 @@ typedef enum { RRC_DEDICATED_RECONF, RRC_PDUSESSION_ESTABLISH, RRC_PDUSESSION_MODIFY, - RRC_PDUSESSION_RELEASE + RRC_PDUSESSION_RELEASE, + RRC_UECAPABILITY_ENQUIRY, } rrc_action_t; typedef struct gNB_RRC_UE_s { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7cd37f08ba..fe2b8c47ea 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1231,6 +1231,10 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, AssertFatal(ue_context_p != NULL, "Processing %s() for UE %lx, ue_context_p is NULL\n", __func__, ctxt_pP->rntiMaybeUEid); gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + int xid = ue_cap_info->rrc_TransactionIdentifier; + DevAssert(UE->xids[xid] == RRC_UECAPABILITY_ENQUIRY); + UE->xids[xid] = RRC_ACTION_NONE; + LOG_I(NR_RRC, "got UE capabilities for UE %lx\n", ctxt_pP->rntiMaybeUEid); int eutra_index = -1; @@ -2471,19 +2475,15 @@ rrc_gNB_generate_UECapabilityEnquiry( uint8_t size; T(T_ENB_RRC_UE_CAPABILITY_ENQUIRY, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rntiMaybeUEid)); - size = do_NR_SA_UECapabilityEnquiry( - ctxt_pP, - buffer, - 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 NR UECapabilityEnquiry (bytes %d)\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), - size); + gNB_RRC_UE_t *ue = &ue_context_pP->ue_context; + uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); + ue->xids[xid] = RRC_UECAPABILITY_ENQUIRY; + size = do_NR_SA_UECapabilityEnquiry(ctxt_pP, buffer, xid); + LOG_I(NR_RRC, "UE %d: Logical Channel DL-DCCH, Generate NR UECapabilityEnquiry (bytes %d)\n", ue->rrc_ue_id, size); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); - const gNB_RRC_UE_t *ue = &ue_context_pP->ue_context; nr_rrc_transfer_protected_rrc_message(rrc, ue, DCCH, buffer, size); } From d2cd7c862a2c0e716134a420d5126826694d8e09 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 12:57:33 +0100 Subject: [PATCH 44/47] Add transactions IDs to logs for RRC reconfig/uecap enq --- openair2/RRC/NR/rrc_gNB.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index fe2b8c47ea..f229222788 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -582,11 +582,7 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co for (int i = 0; i < ue_p->nb_of_pdusessions; i++) clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); - LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate NR_RRCReconfiguration (bytes %d, UE id %x)\n", - ctxt_pP->module_id, - ctxt_pP->frame, - size, - ue_context_pP->ue_context.rnti); + LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d, xid %d)\n", ue_p->rrc_ue_id, size, xid); AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size); @@ -657,7 +653,7 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, ue_p->DRB_ReleaseList); ue_p->DRB_ReleaseList = NULL; - LOG_I(NR_RRC, "[gNB %d] Frame %d, Logical Channel DL-DCCH, Generate RRCReconfiguration (bytes %d, UE RNTI %x)\n", ctxt_pP->module_id, ctxt_pP->frame, size, ue_p->rnti); + LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d, xid %d)\n", ue_p->rrc_ue_id, size, xid); LOG_D(NR_RRC, "[FRAME %05d][RRC_gNB][MOD %u][][--- PDCP_DATA_REQ/%d Bytes (rrcReconfiguration to UE %x MUI %d) --->][PDCP][MOD %u][RB %u]\n", ctxt_pP->frame, @@ -1235,7 +1231,7 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, DevAssert(UE->xids[xid] == RRC_UECAPABILITY_ENQUIRY); UE->xids[xid] = RRC_ACTION_NONE; - LOG_I(NR_RRC, "got UE capabilities for UE %lx\n", ctxt_pP->rntiMaybeUEid); + LOG_I(NR_RRC, "UE %d: received UE capabilities (xid %d)\n", UE->rrc_ue_id, xid); int eutra_index = -1; if (ue_cap_info->criticalExtensions.present == NR_UECapabilityInformation__criticalExtensions_PR_ueCapabilityInformation) { @@ -1409,12 +1405,12 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ rrc_gNB_ue_context_t *ue_context_p, const NR_RRCReconfigurationComplete_t *reconfig_complete) { - LOG_I(NR_RRC, "Receive RRC Reconfiguration Complete message UE %lx\n", ctxt_pP->rntiMaybeUEid); AssertFatal(ue_context_p != NULL, "Processing %s() for UE %lx, ue_context_p is NULL\n", __func__, ctxt_pP->rntiMaybeUEid); gNB_RRC_UE_t *UE = &ue_context_p->ue_context; uint8_t xid = reconfig_complete->rrc_TransactionIdentifier; UE->ue_reconfiguration_counter++; + LOG_I(NR_RRC, "UE %d: Receive RRC Reconfiguration Complete message (xid %d\n)", UE->rrc_ue_id, xid); bool successful_reconfig = true; switch (UE->xids[xid]) { @@ -2479,7 +2475,7 @@ rrc_gNB_generate_UECapabilityEnquiry( uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue->xids[xid] = RRC_UECAPABILITY_ENQUIRY; size = do_NR_SA_UECapabilityEnquiry(ctxt_pP, buffer, xid); - LOG_I(NR_RRC, "UE %d: Logical Channel DL-DCCH, Generate NR UECapabilityEnquiry (bytes %d)\n", ue->rrc_ue_id, size); + LOG_I(NR_RRC, "UE %d: Logical Channel DL-DCCH, Generate NR UECapabilityEnquiry (bytes %d, xid %d)\n", ue->rrc_ue_id, size, xid); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); From d6dd87ae8ca5e95ee9efea109d0e05d4a56bd67f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 14:29:19 +0100 Subject: [PATCH 45/47] RRC transaction IDs: clean up - Put consistently transaction IDs - Remove transaction IDs when transaction finished, or in places that do not trigger an RRC transaction --- openair2/RRC/NR/rrc_gNB.c | 14 +++++++++++--- openair2/RRC/NR/rrc_gNB_NGAP.c | 2 -- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f229222788..7b5a5b6a1b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -939,8 +939,7 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co int i = 0; - uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); - ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; + ue_p->xids[xid] = RRC_ACTION_NONE; ue_p->StatusRrc = NR_RRC_CONNECTED; ue_p->Srb[1].Active = 1; @@ -972,6 +971,8 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, true); NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true); + 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}; int size = do_RRCReconfiguration(ue_p, buffer, @@ -1343,6 +1344,8 @@ static int handle_rrcSetupComplete(const protocol_ctxt_t *const ctxt_pP, return -1; } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + uint8_t xid = setup_complete->rrc_TransactionIdentifier; + UE->xids[xid] = RRC_ACTION_NONE; NR_RRCSetupComplete_IEs_t *setup_complete_ies = setup_complete->criticalExtensions.choice.rrcSetupComplete; @@ -1410,7 +1413,7 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ uint8_t xid = reconfig_complete->rrc_TransactionIdentifier; UE->ue_reconfiguration_counter++; - LOG_I(NR_RRC, "UE %d: Receive RRC Reconfiguration Complete message (xid %d\n)", UE->rrc_ue_id, xid); + LOG_I(NR_RRC, "UE %d: Receive RRC Reconfiguration Complete message (xid %d)\n", UE->rrc_ue_id, xid); bool successful_reconfig = true; switch (UE->xids[xid]) { @@ -1444,6 +1447,11 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ break; } UE->xids[xid] = RRC_ACTION_NONE; + for (int i = 0; i < 3; ++i) { + if (UE->xids[i] != RRC_ACTION_NONE) { + LOG_I(RRC, "UE %d: transaction %d still ongoing for action %d\n", UE->rrc_ue_id, i, UE->xids[i]); + } + } gNB_RRC_INST *rrc = RC.nrrrc[0]; f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index b74a9a759c..4a928ff5de 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -456,8 +456,6 @@ static void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdu } } } - int xid = rrc_gNB_get_next_transaction_identifier(0); - UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; /* Limitation: we assume one fixed CU-UP per UE. We base the selection on * NSSAI, but the UE might have multiple PDU sessions with differing slices, * in which we might need to select different CU-UPs. In this case, we would From 0f100a6e9429d7d587d41f2ad3bf34797e401924 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Feb 2024 10:00:53 +0100 Subject: [PATCH 46/47] Delay PDU session resource setup request if necessary The next commit moves the UE Capability Enquiry after the first reconfiguration. This has the effect that for some UEs (e.g., iPhone), the Setup Requests come too close to each other, triggering RRC Reconfigurations while previous transactions are ongoing. I think the "true" solution would be to implement some tracking of transactions across RRC, F1AP, E1AP, but this might require many changes. For the moment, limit to delaying PDU session resource setups to prevent above problem. Delaying is done using ITTI timers (to be able to serve other UEs), waiting 10ms each time, up to 20 times (to not deadlock the transaction -- after all, if the UE is unhappy, it will drop the connection). --- openair2/RRC/NR/nr_rrc_defs.h | 3 +++ openair2/RRC/NR/rrc_gNB.c | 7 ++--- openair2/RRC/NR/rrc_gNB_NGAP.c | 40 ++++++++++++++++++++++++++++ openair2/RRC/NR/rrc_gNB_UE_context.c | 1 + 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 1aed82e4a0..b26ff1e50c 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -308,6 +308,9 @@ typedef struct gNB_RRC_UE_s { /* Nas Pdu */ ngap_pdu_t nas_pdu; + /* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */ + int max_delays_pdu_session; + } gNB_RRC_UE_t; typedef struct rrc_gNB_ue_context_s { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7b5a5b6a1b..bf0216621f 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2246,9 +2246,10 @@ void *rrc_gnb_task(void *args_p) { break; case TIMER_HAS_EXPIRED: - /* only this one handled for now */ - DevAssert(TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id); - write_rrc_stats(RC.nrrrc[0]); + if (TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id) + write_rrc_stats(RC.nrrrc[0]); + else + itti_send_msg_to_task(TASK_RRC_GNB, 0, TIMER_HAS_EXPIRED(msg_p).arg); /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */ break; case F1AP_INITIAL_UL_RRC_MESSAGE: diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 4a928ff5de..fee0f25b6a 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -820,6 +820,28 @@ rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP( return; } +/* \brief checks if any transaction is ongoing for any xid of this UE */ +static bool transaction_ongoing(const gNB_RRC_UE_t *UE) +{ + for (int xid = 0; xid < 4; ++xid) + if (UE->xids[xid] != RRC_ACTION_NONE) + return true; + return false; +} + +/* \brief delays the ongoing transaction (in msg_p) by setting a timer to wait + * 10ms; upon expiry, delivers to RRC, which sends the message to itself */ +static void delay_transaction(MessageDef *msg_p, int wait_us) +{ + MessageDef *new = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQ); + ngap_pdusession_setup_req_t *n = &NGAP_PDUSESSION_SETUP_REQ(new); + *n = NGAP_PDUSESSION_SETUP_REQ(msg_p); + + int instance = msg_p->ittiMsgHeader.originInstance; + long timer_id; + timer_setup(0, wait_us, TASK_RRC_GNB, instance, TIMER_ONE_SHOT, new, &timer_id); +} + //------------------------------------------------------------------------------ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t instance) //------------------------------------------------------------------------------ @@ -845,6 +867,24 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins AssertFatal(UE->rrc_ue_id == msg->gNB_ue_ngap_id, "logic bug\n"); UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; + + /* This is a hack. We observed that with some UEs, PDU session requests might + * come in quick succession, faster than the RRC reconfiguration for the PDU + * session requests can be carried out (UE is doing reconfig, and second PDU + * session request arrives). We don't have currently the means to "queue up" + * these transactions, which would probably involve some rework of the RRC. + * To still allow these requests to come in and succeed, we below check and delay transactions + * for 10ms. However, to not accidentally end up in infinite loops, the + * maximum number is capped on a per-UE basis as indicated in variable + * max_delays_pdu_session. */ + if (UE->max_delays_pdu_session > 0 && transaction_ongoing(UE)) { + int wait_us = 10000; + LOG_D(RRC, "UE %d: delay PDU session setup by %d us, pending %d retries\n", UE->rrc_ue_id, wait_us, UE->max_delays_pdu_session); + delay_transaction(msg_p, wait_us); + UE->max_delays_pdu_session--; + return; + } + trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink); return; } diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.c b/openair2/RRC/NR/rrc_gNB_UE_context.c index db082c1965..c255488f4e 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.c +++ b/openair2/RRC/NR/rrc_gNB_UE_context.c @@ -188,6 +188,7 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id, "UE F1 Context for ID %d already exists, logic bug\n", ue->rrc_ue_id); cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data); + ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */ RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p); LOG_I(NR_RRC, From 4a7d7975cee687131e7e413c91bd264a1da8d870 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jan 2024 18:22:25 +0100 Subject: [PATCH 47/47] Send RRC UECapabilityEnquiry after reconfig, trigger UE update if necessary We used to trigger the UECapabilityEnquiry right after SecurityModeComplete, and before the RRCReconfiguration (which we call "default" reconfiguration). However, 38.401 tells us that we should send the RRCReconfiguration right after the SecurityModeComplete. In fact, even though we get the UE capabilities, we cannot use them during this reconfiguration, as we would first need to update the DU with a UE Context Modification Request, which we cannot, as we just sent the UE Context Setup Request, and the DU relies on first getting the RRCReconfiguration. Since we rely on a subsequent reconfiguration anyway, we can safely trigger the UECapabilityEnquiry after RRCReconfigurationComplete. (38.331 also says we can send UECapabilityEnquiry at any point.) To cater for the possibility that there might not be any reconfiguration coming afterwards, we check if a DRB has been set up. If not, we assume a reconfiguration will come, and do not trigger one only for the UE capabilities (this is what we do before this commit). If we already have DRBs set up, they might have been set up during the "default" RRC Reconfiguration, and another reconfiguration might not follow soon; in this case, we trigger the reconfiguration by sending the UE capabilities to the DU right away. --- openair2/RRC/NR/rrc_gNB.c | 69 ++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index bf0216621f..2377c2c275 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -596,7 +596,20 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; + /* hack: in many cases, we want to send a PDU session resource setup response + * after this dedicated RRC Reconfiguration (e.g., new PDU session). However, + * this is not always the case, e.g., when the PDU sessions came through the + * NG initial UE context setup, in which case all PDU sessions are + * established, and we end up here after a UE Capability Enquiry. So below, + * check if we are currently setting up any PDU sessions, and only then, set + * the xid to trigger a PDU session setup response. */ + ue_p->xids[xid] = RRC_DEDICATED_RECONF; + for (int i = 0; i < ue_p->nb_of_pdusessions; ++i) { + if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { + ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; + break; + } + } struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { @@ -1325,12 +1338,34 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, ue_cap_info); - // we send the UE capabilities request before RRC connection is complete, - // so we cannot have a PDU session yet - AssertFatal(UE->nb_of_pdusessions == 0, "logic bug: received capabilities while PDU session established\n"); - // TODO: send UE context modification response with UE capabilities to - // allow DU configure CellGroupConfig - rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); + /* if we already have DRBs setup (SRB2 exists if there is at least one DRB), + * there might not be a further reconfiguration on which we can rely, so send + * the UE capabilities to the DU to have it trigger a reconfiguration. */ + if (UE->Srb[2].Active && UE->ue_cap_buffer.len > 0 && UE->ue_cap_buffer.buf != NULL) { + cu_to_du_rrc_information_t cu2du = {0}; + if (UE->ue_cap_buffer.len > 0 && UE->ue_cap_buffer.buf != NULL) { + cu2du.uE_CapabilityRAT_ContainerList = UE->ue_cap_buffer.buf; + cu2du.uE_CapabilityRAT_ContainerList_length = UE->ue_cap_buffer.len; + } + + f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); + if (ue_data.du_assoc_id == 0) { + LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); + return -1; + } + gNB_RRC_INST *rrc = RC.nrrrc[0]; + f1ap_ue_context_modif_req_t ue_context_modif_req = { + .gNB_CU_ue_id = UE->rrc_ue_id, + .gNB_DU_ue_id = ue_data.secondary_ue, + .plmn.mcc = rrc->configuration.mcc[0], + .plmn.mnc = rrc->configuration.mnc[0], + .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], + .nr_cellid = rrc->nr_cellid, + .servCellId = 0, /* TODO: correct value? */ + .cu_to_du_rrc_information = &cu2du, + }; + rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); + } return 0; } @@ -1467,6 +1502,14 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ .ReconfigComplOutcome = successful_reconfig ? RRCreconf_success : RRCreconf_failure, }; rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); + + /* if we did not receive any UE Capabilities, let's do that now. It should + * only happen on the first time a reconfiguration arrives. Afterwards, we + * should have them. If the UE does not give us anything, we will re-request + * the capabilities after each reconfiguration, which is a finite number */ + if (UE->ue_cap_buffer.len == 0) { + rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); + } } //----------------------------------------------------------------------------- int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, @@ -1574,24 +1617,18 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, nr_rrc_pdcp_config_security(ctxt_pP, ue_context_p, 1); ue_context_p->ue_context.as_security_active = true; - rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); + rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); break; case NR_UL_DCCH_MessageType__c1_PR_securityModeFailure: LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)Rx_sdu, sdu_sizeP, "[MSG] NR RRC Security Mode Failure\n"); - LOG_W(NR_RRC, - PROTOCOL_RRC_CTXT_UE_FMT - " RLC RB %02d --- RLC_DATA_IND %d bytes " - "(securityModeFailure) ---> RRC_gNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH, - sdu_sizeP); + LOG_E(NR_RRC, "UE %d: received securityModeFailure\n", ue_context_p->ue_context.rrc_ue_id); if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)ul_dcch_msg); } - rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); + LOG_W(NR_RRC, "Cannot continue as no AS security is activated (implementation missing)\n"); break; case NR_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation: