Allow F1 to be used in do-ra
This is preparatory work to allow NSA-like modes to be used over F1 in the future. Notably, it fills the F1 message for UE context setup with GTP TEID, and fills additional information to "make the F1 encoder happy" (fill in QFI etc). Also, provide some F1 fixes to make this work. Remove stale UE connections, if relevant.
This commit is contained in:
committed by
francescomani
parent
b9edba2186
commit
b4a7a1a194
@@ -262,11 +262,13 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
|
||||
if (f1ap_ue_context_setup_req->cu_to_du_rrc_information!=NULL) {
|
||||
/* optional */
|
||||
/* 6.1 cG_ConfigInfo */
|
||||
if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo!=NULL){
|
||||
if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo_length > 0) {
|
||||
DevAssert(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo != NULL);
|
||||
asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.cG_ConfigInfo, cG_ConfigInfo);
|
||||
OCTET_STRING_fromBuf(cG_ConfigInfo, (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo,
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo_length);
|
||||
}
|
||||
|
||||
/* optional */
|
||||
/* 6.2 uE_CapabilityRAT_ContainerList */
|
||||
if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){
|
||||
|
||||
@@ -178,6 +178,11 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information = (cu_to_du_rrc_information_t *)calloc(1,sizeof(cu_to_du_rrc_information_t));
|
||||
cu_to_du_rrc_information_t *cu2du = f1ap_ue_context_setup_req->cu_to_du_rrc_information;
|
||||
const F1AP_CUtoDURRCInformation_t *cu2duie = &ieCuRrcInfo->value.choice.CUtoDURRCInformation;
|
||||
if (cu2duie->cG_ConfigInfo != NULL) {
|
||||
cu2du->cG_ConfigInfo = malloc_or_fail(cu2duie->cG_ConfigInfo->size);
|
||||
cu2du->cG_ConfigInfo_length = cu2duie->cG_ConfigInfo->size;
|
||||
memcpy(cu2du->cG_ConfigInfo, cu2duie->cG_ConfigInfo->buf, cu2du->cG_ConfigInfo_length);
|
||||
}
|
||||
if(cu2duie->uE_CapabilityRAT_ContainerList!=NULL){
|
||||
cu2du->uE_CapabilityRAT_ContainerList = calloc(1, cu2duie->uE_CapabilityRAT_ContainerList->size);
|
||||
memcpy(cu2du->uE_CapabilityRAT_ContainerList,
|
||||
|
||||
@@ -84,9 +84,14 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c
|
||||
if (req->cu_to_du_rrc_information != NULL) {
|
||||
f1ap_msg->cu_to_du_rrc_information = calloc(1, sizeof(*f1ap_msg->cu_to_du_rrc_information));
|
||||
AssertFatal(f1ap_msg->cu_to_du_rrc_information != NULL, "out of memory\n");
|
||||
AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL && req->cu_to_du_rrc_information->cG_ConfigInfo_length == 0, "cg_ConfigInfo not implemented\n");
|
||||
AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n");
|
||||
const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information;
|
||||
if (req->cu_to_du_rrc_information->cG_ConfigInfo != NULL) {
|
||||
cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information;
|
||||
du2cu_new->cG_ConfigInfo_length = du2cu_req->cG_ConfigInfo_length;
|
||||
du2cu_new->cG_ConfigInfo = malloc_or_fail(du2cu_new->cG_ConfigInfo_length);
|
||||
memcpy(du2cu_new->cG_ConfigInfo, du2cu_req->cG_ConfigInfo, du2cu_new->cG_ConfigInfo_length);
|
||||
}
|
||||
AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n");
|
||||
if (req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList != NULL) {
|
||||
cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information;
|
||||
DevAssert(du2cu_req->uE_CapabilityRAT_ContainerList_length > 0);
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
#define NR_MAX_SUPPORTED_DL_LAYERS 4
|
||||
|
||||
void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m);
|
||||
void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id);
|
||||
void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp);
|
||||
void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context);
|
||||
void rrc_remove_nsa_user_context(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context);
|
||||
|
||||
@@ -261,7 +261,8 @@ static void rrc_gNB_process_AdditionRequestInformation(const module_id_t gnb_mod
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[gnb_mod_idP];
|
||||
AssertFatal(NODE_IS_MONOLITHIC(rrc->node_type), "NSA, phy_test, and do_ra only work in monolithic\n");
|
||||
rrc_add_nsa_user(rrc, m);
|
||||
sctp_assoc_t assoc_id = -1; // monolithic gNB
|
||||
rrc_add_nsa_user(rrc, m, assoc_id);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -440,12 +440,14 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
||||
|
||||
/* we need to setup one default UE for phy-test and do-ra modes in the MAC */
|
||||
if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0)
|
||||
rrc_add_nsa_user(rrc, NULL);
|
||||
rrc_add_nsa_user(rrc, NULL, assoc_id);
|
||||
}
|
||||
|
||||
static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||
{
|
||||
int count = 0;
|
||||
seq_arr_t ue_context_to_remove;
|
||||
seq_arr_init(&ue_context_to_remove, sizeof(rrc_gNB_ue_context_t *));
|
||||
rrc_gNB_ue_context_t *ue_context_p = NULL;
|
||||
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) {
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
@@ -455,7 +457,7 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||
nr_rrc_finalize_ho(UE);
|
||||
}
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
|
||||
if (ue_data.du_assoc_id == assoc_id) {
|
||||
if (ue_data.du_assoc_id == assoc_id && IS_SA_MODE(get_softmodem_params())) {
|
||||
/* this UE belongs to the DU that disconnected, set du_assoc_id to 0,
|
||||
* meaning DU is offline, then trigger release request */
|
||||
ue_data.du_assoc_id = 0;
|
||||
@@ -464,8 +466,17 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RADIO_CONNECTION_WITH_UE_LOST};
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(0, ue_context_p, cause);
|
||||
count++;
|
||||
} else {
|
||||
seq_arr_push_back(&ue_context_to_remove, &ue_context_p, sizeof(ue_context_p));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < seq_arr_size(&ue_context_to_remove); ++i) {
|
||||
/* we retrieve a pointer (=iterator) to the UE context pointer
|
||||
* (ue_context_p), so dereference once */
|
||||
rrc_gNB_ue_context_t *p = *(rrc_gNB_ue_context_t **)seq_arr_at(&ue_context_to_remove, i);
|
||||
rrc_remove_nsa_user_context(rrc, p);
|
||||
}
|
||||
seq_arr_free(&ue_context_to_remove, NULL);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
#include "x2ap_messages_types.h"
|
||||
#include "xer_decoder.h"
|
||||
#include "xer_encoder.h"
|
||||
#include "f1ap_common.h"
|
||||
|
||||
// In case of phy-test and do-ra mode, read UE capabilities directly from file
|
||||
// and put it into a CG-ConfigInfo field
|
||||
@@ -114,16 +115,22 @@ static int cg_config_info_from_ue_cap_file(uint32_t maxlen, uint8_t buf[maxlen])
|
||||
return (rval.encoded + 7) >> 3;
|
||||
}
|
||||
|
||||
static instance_t get_f1_gtp_instance(void)
|
||||
{
|
||||
const f1ap_cudu_inst_t *inst = getCxt(0);
|
||||
if (!inst)
|
||||
return -1; // means no F1
|
||||
return inst->gtpInst;
|
||||
}
|
||||
|
||||
/* generate prototypes for the tree management functions (RB_INSERT used in rrc_add_nsa_user) */
|
||||
RB_PROTOTYPE(rrc_nr_ue_tree_s, rrc_gNB_ue_context_s, entries,
|
||||
rrc_gNB_compare_ue_rnti_id);
|
||||
|
||||
void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m)
|
||||
void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id)
|
||||
{
|
||||
AssertFatal(!IS_SA_MODE(get_softmodem_params()), "%s() cannot be called in SA mode, it is intrinsically for NSA\n", __func__);
|
||||
AssertFatal(NODE_IS_MONOLITHIC(rrc->node_type), "NSA, phy_test and do_ra only work in monolithic\n");
|
||||
|
||||
sctp_assoc_t assoc_id = -1; /* integrated DU, hardcoded: if multiple we would not know what to do? */
|
||||
/* all the 0 are DU-related info that we will fill later, see rrc_add_nsa_user_resp() below */
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_create_ue_context(assoc_id, 0, rrc, 0, 0);
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
@@ -273,12 +280,36 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m)
|
||||
/* assumption: only a single bearer, see above */
|
||||
NR_DRB_ToAddModList_t *rb_list = UE->rb_config->drb_ToAddModList;
|
||||
AssertFatal(rb_list->list.count == 1, "can only handle one bearer for NSA/phy-test/do-ra, but has %d\n", rb_list->list.count);
|
||||
int drb_id = rb_list->list.array[0]->drb_Identity;
|
||||
f1ap_flows_mapped_to_drb_t *flow = calloc(1, sizeof(f1ap_flows_mapped_to_drb_t));
|
||||
flow->qos_params.qos_characteristics.qos_type = NON_DYNAMIC;
|
||||
flow->qfi = flow->qos_params.qos_characteristics.non_dynamic.fiveqi = 9;
|
||||
f1ap_drb_to_be_setup_t drbs = {
|
||||
.drb_id = rb_list->list.array[0]->drb_Identity,
|
||||
.drb_id = drb_id,
|
||||
.rlc_mode = F1AP_RLC_MODE_UM_BIDIR, // hardcoded keep it backwards compatible for now
|
||||
// rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM,
|
||||
.up_ul_tnl_length = 1,
|
||||
.drb_info.flows_to_be_setup_length = 1,
|
||||
.drb_info.flows_mapped_to_drb = flow,
|
||||
};
|
||||
// Note: E1 support for NSA/phy-test/do-ra not implemented yet
|
||||
instance_t f1inst = get_f1_gtp_instance();
|
||||
if (f1inst >= 0) {
|
||||
gtpv1u_gnb_create_tunnel_req_t req = {
|
||||
.ue_id = UE->rrc_ue_id,
|
||||
.incoming_rb_id[0] = drb_id,
|
||||
.pdusession_id[0] = drb_id,
|
||||
.outgoing_teid[0] = 0xffff, // will be updated later
|
||||
.dst_addr[0].length = 32,
|
||||
.num_tunnels = 1,
|
||||
};
|
||||
gtpv1u_gnb_create_tunnel_resp_t resp = {0};
|
||||
int ret = gtpv1u_create_ngu_tunnel(f1inst, &req, &resp, NULL, NULL);
|
||||
AssertFatal(ret == 0, "gtpv1u_create_ngu_tunnel failed: ret %d\n", ret);
|
||||
drbs.up_ul_tnl[0].port = rrc->eth_params_s.my_portd;
|
||||
memcpy(&drbs.up_ul_tnl[0].tl_address, &resp.gnb_addr.buffer, 4);
|
||||
drbs.up_ul_tnl[0].teid = resp.gnb_NGu_teid[0];
|
||||
}
|
||||
f1ap_ue_context_setup_t req = {
|
||||
.gNB_CU_ue_id = UE->rrc_ue_id,
|
||||
.gNB_DU_ue_id = 0xffffffff, /* not known yet */
|
||||
@@ -363,6 +394,19 @@ void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_co
|
||||
bool success = cu_update_f1_ue_data(UE->rrc_ue_id, &ue_data);
|
||||
DevAssert(success);
|
||||
|
||||
instance_t f1inst = get_f1_gtp_instance();
|
||||
if (f1inst >= 0) {
|
||||
// Note: E1 support for NSA/phy-test/do-ra not implemented yet
|
||||
// so set up GTP from here
|
||||
for (int i = 0; i < resp->drbs_to_be_setup_length; ++i) {
|
||||
f1ap_drb_to_be_setup_t *drb = &resp->drbs_to_be_setup[i];
|
||||
DevAssert(drb->up_dl_tnl_length == 1);
|
||||
in_addr_t addr = drb->up_dl_tnl[0].tl_address;
|
||||
uint32_t teid = drb->up_dl_tnl[0].teid;
|
||||
GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, UE->rrc_ue_id, drb->drb_id, addr, teid);
|
||||
}
|
||||
}
|
||||
|
||||
NR_RRCReconfiguration_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_t));
|
||||
reconfig->rrc_TransactionIdentifier = 0;
|
||||
reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration;
|
||||
@@ -405,6 +449,9 @@ void rrc_remove_nsa_user_context(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_con
|
||||
{
|
||||
if (!IS_SOFTMODEM_NOS1)
|
||||
gtpv1u_delete_all_s1u_tunnel(rrc->module_id, ue_context->ue_context.rrc_ue_id);
|
||||
instance_t f1inst = get_f1_gtp_instance();
|
||||
if (f1inst >= 0)
|
||||
gtpv1u_delete_all_s1u_tunnel(f1inst, ue_context->ue_context.rrc_ue_id);
|
||||
// we don't use E1 => we have to free SDAP
|
||||
nr_sdap_delete_ue_entities(ue_context->ue_context.rrc_ue_id);
|
||||
rrc_remove_ue(rrc, ue_context);
|
||||
|
||||
Reference in New Issue
Block a user