Commit 0b2757b3 authored by Robert Schmidt's avatar Robert Schmidt

Implement handler for F1 UE context Setup in HO case

This commit implements adding a new UE on the target DU in case of
handover. We identify this case by the fact that the gNB-CU did not send
a gNB-DU UE ID (which is optional in F1AP, but not in our
implementation), such that we know there is no corresponding UE, which
therefore has to be created.

If it happens that there is a handover preparation information, we read
the UE capabilities from this information, and subsequently trigger the
creation of a new UE.

Another change is that for all bearers that we are asked to setup, we
add reestablishRLC so that the UE does a reestablishment during the
reconfiguration.

As we have to remove the reconfigurationWithSync and reestablishRLC IE
after application of the CellGroupConfig (because we might reuse the
CellGroupConfig later), free these IEs. As there are now multiple fields
to free, introduce a separate nr_mac_clean_cellgroup() function that
handles cleaning of the CellGroupConfig.
Co-authored-by: default avatarbatuhanduyuler <batuhan.duyuler@firecell.io>
Co-authored-by: default avatarrmagueta <rmagueta@allbesmart.pt>
parent e7b56b3d
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment