From 7b9442f58da9455ece3380fa1aecee19b0922c3e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 3 Apr 2025 12:47:32 +0200 Subject: [PATCH] DU-level changes to handle F1 UE Context Setup in NSA/phy-test/do-ra Co-authored-by: Francesco Mani --- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 135 +++++++++++++++--- openair2/LAYER2/NR_MAC_gNB/main.c | 1 - openair2/RRC/NR/nr_rrc_config.c | 6 +- 3 files changed, 113 insertions(+), 29 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 8ba63890ca..9d3850586b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -27,6 +27,7 @@ #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "F1AP_CauseRadioNetwork.h" #include "NR_HandoverPreparationInformation.h" +#include "NR_CG-ConfigInfo.h" #include "openair3/ocp-gtpu/gtp_itf.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" #include "lib/f1ap_interface_management.h" @@ -342,6 +343,8 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE, resp_drb->up_dl_tnl[0].teid = resp_f1.gnb_NGu_teid[0]; } + if (!cellGroupConfig->rlc_BearerToAddModList) + cellGroupConfig->rlc_BearerToAddModList = calloc_or_fail(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); DevAssert(ret == 0); } @@ -461,6 +464,52 @@ static NR_UE_NR_Capability_t *get_ue_nr_cap_from_ho_prep_info(uint8_t *buf, uint return cap; } +static NR_CG_ConfigInfo_t *get_cg_config_info(uint8_t *buf, uint32_t len) +{ + struct NR_CG_ConfigInfo *cg_configinfo = NULL; + asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_CG_ConfigInfo, (void **)&cg_configinfo, buf, len); + if (dec_rval.code != RC_OK) { + LOG_W(NR_MAC, "cannot decode CG-ConfigInfo, ignoring it\n"); + return NULL; + } + //xer_fprint(stdout, &asn_DEF_NR_CG_ConfigInfo, cg_configinfo); + return cg_configinfo; +} + +static NR_UE_NR_Capability_t *get_ue_nr_cap_from_cg_config_info(const NR_CG_ConfigInfo_t *cgci) +{ + /* INTO DU handler */ + if (cgci->criticalExtensions.present != NR_CG_ConfigInfo__criticalExtensions_PR_c1) + return NULL; + if (!cgci->criticalExtensions.choice.c1 + || cgci->criticalExtensions.choice.c1->present != NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo) + return NULL; + + const NR_CG_ConfigInfo_IEs_t *cgci_ie = cgci->criticalExtensions.choice.c1->choice.cg_ConfigInfo; + if (!cgci_ie->ue_CapabilityInfo) + return NULL; + + // Decode UE-CapabilityRAT-ContainerList + const OCTET_STRING_t *cap_buf = cgci_ie->ue_CapabilityInfo; + NR_UE_CapabilityRAT_ContainerList_t *clist = NULL; + asn_dec_rval_t dec_rval = uper_decode_complete(NULL, + &asn_DEF_NR_UE_CapabilityRAT_ContainerList, + (void **)&clist, + cap_buf->buf, + cap_buf->size); + + if (dec_rval.code != RC_OK) { + LOG_W(NR_MAC, + "Failed to decode NR_UE_CapabilityRAT_ContainerList (%zu bits), size of OCTET_STRING %lu\n", + dec_rval.consumed, + cap_buf->size); + return NULL; + } + NR_UE_NR_Capability_t *cap = get_nr_cap(clist); + ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, clist); + return cap; +} + NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig) { uint8_t buf[16636]; @@ -473,45 +522,75 @@ NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig) return cloned; } -static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id) +static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id, const NR_CG_ConfigInfo_t *cgci) { + const bool is_SA = IS_SA_MODE(get_softmodem_params()); int CC_id = 0; rnti_t rnti; - bool found = nr_mac_get_new_rnti(&mac->UE_info, &rnti); - if (!found) - return NULL; - - NR_UE_info_t *UE = get_new_nr_ue_inst(&mac->UE_info.uid_allocator, rnti, NULL); - AssertFatal(UE != NULL, "cannot create UE context, UE context setup failure not implemented\n"); - if (!add_new_UE_RA(mac, UE)) { - delete_nr_ue_data(UE, /*not used*/ NULL, &mac->UE_info.uid_allocator); - LOG_E(NR_MAC, "UE list full while creating new UE\n"); - return NULL; + if (get_softmodem_params()->phy_test) { + AssertFatal(mac->UE_info.connected_ue_list[0] == NULL, "phytest: UE already present\n"); + rnti = 0x1234; + } else { + bool found = nr_mac_get_new_rnti(&mac->UE_info, &rnti); + if (!found) + return NULL; } f1_ue_data_t new_ue_data = {.secondary_ue = cu_id}; bool success = du_add_f1_ue_data(rnti, &new_ue_data); DevAssert(success); - const NR_ServingCellConfigCommon_t *scc = mac->common_channels[CC_id].ServingCellConfigCommon; - const NR_ServingCellConfig_t *sccd = mac->common_channels[CC_id].pre_ServingCellConfig; - NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config); - cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc); + NR_UE_info_t *UE = get_new_nr_ue_inst(&mac->UE_info.uid_allocator, rnti, NULL); + AssertFatal(UE != NULL, "cannot create UE context, UE context setup failure not implemented\n"); + + NR_CellGroupConfig_t *cellGroupConfig = NULL; + NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; + const NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + const NR_ServingCellConfig_t *sccd = cc->pre_ServingCellConfig; + const nr_mac_config_t *configuration = &mac->radio_config; + if (is_SA) { + cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config); + cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc); + } else { + NR_UE_NR_Capability_t *cap = get_ue_nr_cap_from_cg_config_info(cgci); + cellGroupConfig = get_default_secondaryCellGroup(scc, sccd, cap, 1, 1, configuration, UE->uid); + // TODO: fixme: gives a new random RNTI + UE->rnti = cellGroupConfig->spCellConfig->reconfigurationWithSync->newUE_Identity; + // TODO: in NSA we assign capabilities here, otherwise outside => not logic + UE->capability = cap; + } // note: we don't pass the cellGroupConfig to add_new_nr_ue() because we need // the uid to create the CellGroupConfig (which is in the UE context created // by add_new_nr_ue(); it's a kind of chicken-and-egg problem), so below we // complete the UE context with the information that add_new_nr_ue() would // have added + AssertFatal(cellGroupConfig != NULL, "out of memory\n"); UE->CellGroup = cellGroupConfig; - nr_rlc_activate_srb0(UE->rnti, UE, NULL); - nr_mac_prepare_ra_ue(mac, UE); - /* SRB1 is added to RLC and MAC in the handler later */ + if (get_softmodem_params()->phy_test) { + // phytest mode: we don't set up RA, etc + free_and_zero(UE->ra); // test-mode: UE will not do RA + bool res = add_connected_nr_ue(mac, UE); + DevAssert(res); + } else { + if (!add_new_UE_RA(mac, UE)) { + delete_nr_ue_data(UE, /*not used*/ NULL, &mac->UE_info.uid_allocator); + LOG_E(NR_MAC, "UE list full while creating new UE\n"); + return NULL; + } + nr_mac_prepare_ra_ue(mac, UE); + + if (is_SA) { + /* SRB1 is added to RLC and MAC in the handler later */ + nr_rlc_activate_srb0(UE->rnti, UE, NULL); + } + } return UE; } void ue_context_setup_request(const f1ap_ue_context_setup_t *req) { + const bool is_SA = IS_SA_MODE(get_softmodem_params()); gNB_MAC_INST *mac = RC.nrmac[0]; /* response has same type as request... */ f1ap_ue_context_setup_t resp = { @@ -525,9 +604,11 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) bool ue_id_provided = resp.gNB_DU_ue_id > 0 && resp.gNB_DU_ue_id < 0xffff; NR_UE_NR_Capability_t *ue_cap = NULL; + NR_CG_ConfigInfo_t *cg_configinfo = NULL; if (req->cu_to_du_rrc_information != NULL) { const cu_to_du_rrc_information_t *cu2du = req->cu_to_du_rrc_information; - AssertFatal(cu2du->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n"); + if (cu2du->cG_ConfigInfo != NULL) + cg_configinfo = get_cg_config_info(cu2du->cG_ConfigInfo, cu2du->cG_ConfigInfo_length); if (cu2du->handoverPreparationInfo != NULL) { ue_cap = get_ue_nr_cap_from_ho_prep_info(cu2du->handoverPreparationInfo, cu2du->handoverPreparationInfo_length); } else if (cu2du->uE_CapabilityRAT_ContainerList != NULL) { @@ -535,15 +616,21 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) } AssertFatal(cu2du->measConfig == NULL, "MeasConfig not handled\n"); } + /* 38.473: "For DC operation, the CG-ConfigInfo IE shall be included in the CU + * to DU RRC Information IE at the gNB acting as secondary node" As of now, + * we only handle NSA => we check we have CG-ConfigInfo if not SA or have SA + * and no CG-ConfigInfo */ + AssertFatal(is_SA ^ (cg_configinfo != NULL), "cannot have SA and CG-ConfigInfo: NR-DC not supported xor need CG-ConfigInfo for NSA/phy-test/do-ra\n"); NR_SCHED_LOCK(&mac->sched_lock); NR_UE_info_t *UE = NULL; if (!ue_id_provided) { - UE = create_new_UE(mac, req->gNB_CU_ue_id); + UE = create_new_UE(mac, req->gNB_CU_ue_id, cg_configinfo); resp.gNB_DU_ue_id = UE->rnti; resp.crnti = &UE->rnti; } else { + DevAssert(is_SA); UE = find_nr_UE(&mac->UE_info, req->gNB_DU_ue_id); } AssertFatal(UE, "no UE found or could not be created, but UE Context Setup Failed not implemented\n"); @@ -573,12 +660,13 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; UE->capability = ue_cap; - if (ue_cap != NULL) { + if (ue_cap != NULL && cg_configinfo == NULL) { // store the new UE capabilities, and update the cellGroupConfig + // only to be done if we did not already update through the cg_configinfo update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc); } - if (!ue_id_provided) { + if (!ue_id_provided && cg_configinfo == NULL) { /* new UE: tell the UE to reestablish RLC */ struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod = new_CellGroup->rlc_BearerToAddModList; for (int i = 0; i < addmod->list.count; ++i) { @@ -601,7 +689,8 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = new_CellGroup; - configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); + int ss_type = cg_configinfo ? NR_SearchSpace__searchSpaceType_PR_ue_Specific: NR_SearchSpace__searchSpaceType_PR_common; + configure_UE_BWP(mac, scc, UE, false, ss_type, -1, -1); NR_SCHED_UNLOCK(&mac->sched_lock); diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 20602b8641..1ca1da1dc2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -329,7 +329,6 @@ void mac_top_init_gNB(ngran_node_t node_type, // setup PDCP, RLC nr_pdcp_entity_security_keys_and_algos_t null_security_parameters = {0}; nr_pdcp_add_drbs(ENB_FLAG_NO, 0x1234, rbconfig->drb_ToAddModList, &null_security_parameters); - nr_rlc_add_drb(0x1234, rbconfig->drb_ToAddModList->list.array[0]->drb_Identity, rlc_rbconfig); // free memory free_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 4c95b435c6..1938f4b9bc 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -3559,12 +3559,8 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC NR_CellGroupConfig_t *secondaryCellGroup = calloc(1, sizeof(*secondaryCellGroup)); secondaryCellGroup->cellGroupId = scg_id; - /* LCID is 4 because the RLC layer requires it to be 3+rb_id; the rb_id is 1 - * for first RB. We pre-configure RLC UM Bi-directional, priority is 1 */ - NR_RLC_BearerConfig_t *RLC_BearerConfig = get_DRB_RLC_BearerConfig(4, 1, NR_RLC_Config_PR_um_Bi_Directional, 1); - secondaryCellGroup->rlc_BearerToAddModList = calloc(1, sizeof(*secondaryCellGroup->rlc_BearerToAddModList)); - asn1cSeqAdd(&secondaryCellGroup->rlc_BearerToAddModList->list, RLC_BearerConfig); + /* rlc_BearerToAddModList is handled outside */ secondaryCellGroup->mac_CellGroupConfig = configure_mac_cellgroup(&configuration->timer_config); secondaryCellGroup->physicalCellGroupConfig = configure_phy_cellgroup();