DU-level changes to handle F1 UE Context Setup in NSA/phy-test/do-ra

Co-authored-by: Francesco Mani <email@francescomani.it>
This commit is contained in:
Robert Schmidt
2025-05-04 09:34:41 +02:00
committed by francescomani
co-authored by Francesco Mani
parent 6c5514d5c9
commit 7b9442f58d
3 changed files with 113 additions and 29 deletions
+112 -23
View File
@@ -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);
-1
View File
@@ -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);
+1 -5
View File
@@ -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();