diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index d171afaacb..f4bffe6144 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -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){ diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 98de177af1..cd9b2865c9 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -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, diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index ff89f61160..9fef2dea58 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -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); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index b8aab08edb..c5627b6e55 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -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); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b7e452fd73..13445a8e8d 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -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); } //----------------------------------------------------------------------------- diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index aff74fc984..8aec9a634b 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -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; } diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 2683f10a41..120a400bbf 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -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);