diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index b091cf69ee..0b09bb78a9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2950,6 +2950,25 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo } } +static void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) +{ + /* remove a reconfigurationWithSync, we don't need it anymore */ + if (cell_group->spCellConfig->reconfigurationWithSync != NULL) { + ASN_STRUCT_FREE(asn_DEF_NR_ReconfigurationWithSync, cell_group->spCellConfig->reconfigurationWithSync); + cell_group->spCellConfig->reconfigurationWithSync = NULL; + } + /* remove the rlc_BearerToReleaseList, we don't need it anymore */ + if (cell_group->rlc_BearerToReleaseList != NULL) { + struct NR_CellGroupConfig__rlc_BearerToReleaseList *l = cell_group->rlc_BearerToReleaseList; + asn_sequence_del(&l->list, l->list.count, /* free */ 1); + free(cell_group->rlc_BearerToReleaseList); + cell_group->rlc_BearerToReleaseList = NULL; + } + /* remove reestablishRLC, we don't need it anymore */ + for (int i = 0; i < cell_group->rlc_BearerToAddModList->list.count; ++i) + free_and_zero(cell_group->rlc_BearerToAddModList->list.array[i]->reestablishRLC); +} + static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot) { LOG_D(NR_MAC, "%4d.%2d RNTI %04x: UE inactivity timer expired\n", frame, slot, UE->rnti); @@ -2965,13 +2984,7 @@ static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)UE->CellGroup); - /* remove the rlc_BearerToReleaseList, we don't need it anymore */ - if (UE->CellGroup->rlc_BearerToReleaseList != NULL) { - struct NR_CellGroupConfig__rlc_BearerToReleaseList *l = UE->CellGroup->rlc_BearerToReleaseList; - asn_sequence_del(&l->list, l->list.count, /* free */1); - free(UE->CellGroup->rlc_BearerToReleaseList); - UE->CellGroup->rlc_BearerToReleaseList = NULL; - } + nr_mac_clean_cellgroup(UE->CellGroup); } NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; 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 a6193580de..4089b224d1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -26,6 +26,7 @@ #include "openair2/F1AP/f1ap_common.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "F1AP_CauseRadioNetwork.h" +#include "NR_HandoverPreparationInformation.h" #include "openair3/ocp-gtpu/gtp_itf.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" #include "lib/f1ap_interface_management.h" @@ -419,6 +420,35 @@ static NR_UE_NR_Capability_t *get_ue_nr_cap(int rnti, uint8_t *buf, uint32_t len return cap; } +/* \brief return UE capabilties from HandoverPreparationInformation. + * + * The HandoverPreparationInformation contains more, but for the moment, let's + * keep it simple and only handle that. The function asserts if other IEs are + * present. */ +static NR_UE_NR_Capability_t *get_ue_nr_cap_from_ho_prep_info(uint8_t *buf, uint32_t len) +{ + if (buf == NULL || len == 0) + return NULL; + NR_HandoverPreparationInformation_t *hpi = NULL; + asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_HandoverPreparationInformation, (void **)&hpi, buf, len); + if (dec_rval.code != RC_OK) { + LOG_W(NR_MAC, "cannot decode HandoverPreparationInformation, ignoring capabilities\n"); + return NULL; + } + NR_UE_NR_Capability_t *cap = NULL; + if (hpi->criticalExtensions.present != NR_HandoverPreparationInformation__criticalExtensions_PR_c1 + || hpi->criticalExtensions.choice.c1 == NULL + || hpi->criticalExtensions.choice.c1->present + != NR_HandoverPreparationInformation__criticalExtensions__c1_PR_handoverPreparationInformation + || hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation == NULL) { + } else { + const NR_HandoverPreparationInformation_IEs_t *hpi_ie = hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation; + cap = get_nr_cap(&hpi_ie->ue_CapabilityRAT_List); + } + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi); + return cap; +} + NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig) { uint8_t buf[16636]; @@ -431,6 +461,40 @@ 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) +{ + int CC_id = 0; + const NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; + rnti_t rnti; + bool found = nr_mac_get_new_rnti(&mac->UE_info, cc->ra, sizeofArray(cc->ra), &rnti); + if (!found) + return NULL; + + NR_UE_info_t* UE = add_new_nr_ue(mac, rnti, NULL); + if (!UE) + return NULL; + + f1_ue_data_t new_ue_data = {.secondary_ue = cu_id}; + du_add_f1_ue_data(rnti, &new_ue_data); + + 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); + // 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 + UE->Msg4_MsgB_ACKed = true; + UE->CellGroup = cellGroupConfig; + + nr_rlc_activate_srb0(UE->rnti, UE, NULL); + nr_mac_prepare_ra_ue(mac, rnti, UE->CellGroup); + /* SRB1 is added to RLC and MAC in the handler later */ + return UE; +} + void ue_context_setup_request(const f1ap_ue_context_setup_t *req) { gNB_MAC_INST *mac = RC.nrmac[0]; @@ -440,19 +504,34 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) .gNB_DU_ue_id = req->gNB_DU_ue_id, }; + /* gNB-DU UE ID is optional. As of now, the F1AP module fills -1 (on uint, so + * 0xffffffff), but the DU uses the RNTI, so check if it's a legal RNTI in + * which case we consider; if not, assume no DU UE ID given */ + bool ue_id_provided = resp.gNB_DU_ue_id > 0 && resp.gNB_DU_ue_id < 0xffff; + NR_UE_NR_Capability_t *ue_cap = NULL; if (req->cu_to_du_rrc_information != NULL) { - AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n"); - ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id, - req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, - req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); - AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL, "MeasConfig not handled\n"); + 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->handoverPreparationInfo != NULL) { + ue_cap = get_ue_nr_cap_from_ho_prep_info(cu2du->handoverPreparationInfo, cu2du->handoverPreparationInfo_length); + } else if (cu2du->uE_CapabilityRAT_ContainerList != NULL) { + ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id, cu2du->uE_CapabilityRAT_ContainerList, cu2du->uE_CapabilityRAT_ContainerList_length); + } + AssertFatal(cu2du->measConfig == NULL, "MeasConfig not handled\n"); } NR_SCHED_LOCK(&mac->sched_lock); - NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, req->gNB_DU_ue_id); - AssertFatal(UE, "did not find UE with RNTI %04x, but UE Context Setup Failed not implemented\n", req->gNB_DU_ue_id); + NR_UE_info_t *UE = NULL; + if (!ue_id_provided) { + UE = create_new_UE(mac, req->gNB_CU_ue_id); + resp.gNB_DU_ue_id = UE->rnti; + resp.crnti = &UE->rnti; + } else { + 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"); NR_CellGroupConfig_t *new_CellGroup = clone_CellGroupConfig(UE->CellGroup); @@ -484,6 +563,14 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc); } + if (!ue_id_provided) { + /* 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) { + asn1cCallocOne(addmod->list.array[i]->reestablishRLC, NR_RLC_BearerConfig__reestablishRLC_true); + } + } + resp.du_to_cu_rrc_information = calloc(1, sizeof(du_to_cu_rrc_information_t)); AssertFatal(resp.du_to_cu_rrc_information != NULL, "out of memory\n"); resp.du_to_cu_rrc_information->cellGroupConfig = calloc(1,1024);