diff --git a/CMakeLists.txt b/CMakeLists.txt index f7e7828285..feb7e41a4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1138,8 +1138,6 @@ set(L2_NR_SRC ${NR_RRC_DIR}/mac_rrc_dl_f1ap.c ${NR_RRC_DIR}/nr_rrc_config.c ${NR_RRC_DIR}/rrc_gNB_nsa.c - ${NR_RRC_DIR}/rrc_gNB_internode.c - ${NR_RRC_DIR}/rrc_gNB_reconfig.c ${NR_RRC_DIR}/rrc_gNB_UE_context.c ${NR_RRC_DIR}/rrc_gNB_NGAP.c ${NR_RRC_DIR}/rrc_gNB_radio_bearers.c @@ -1366,7 +1364,6 @@ include_directories("${OPENAIR1_DIR}/SCHED_NR_UE") ########################## add_library (GTPV1U - ${NR_RRC_DIR}/rrc_gNB_GTPV1U.c ${RRC_DIR}/rrc_eNB_GTPV1U.c ${OPENAIR3_DIR}/ocp-gtpu/gtp_itf.cpp ) diff --git a/ci-scripts/datalog_rt_stats.100.2x2.yaml b/ci-scripts/datalog_rt_stats.100.2x2.yaml index 7b5c8cbbeb..e2bbc6b71d 100644 --- a/ci-scripts/datalog_rt_stats.100.2x2.yaml +++ b/ci-scripts/datalog_rt_stats.100.2x2.yaml @@ -15,10 +15,10 @@ Ref : DLSCH encoding : 220.0 L1 Rx processing : 530.0 PUSCH inner-receiver : 360.0 - Schedule Response : 3.0 - DL & UL scheduling timing : 17.0 - UL Indication : 3.0 - Slot Indication : 17.0 + Schedule Response : 1.0 + DL & UL scheduling timing : 12.0 + UL Indication : 1.0 + Slot Indication : 13.0 DeviationThreshold : feprx : 0.25 feptx_prec : 0.25 diff --git a/ci-scripts/datalog_rt_stats.1x1.60.yaml b/ci-scripts/datalog_rt_stats.1x1.60.yaml index acd8251525..47021b502b 100644 --- a/ci-scripts/datalog_rt_stats.1x1.60.yaml +++ b/ci-scripts/datalog_rt_stats.1x1.60.yaml @@ -15,10 +15,10 @@ Ref : DLSCH encoding : 140.0 L1 Rx processing : 345.0 PUSCH inner-receiver : 150.0 - Schedule Response : 3.0 - DL & UL scheduling timing : 7.0 - UL Indication : 3.0 - Slot Indication : 8.0 + Schedule Response : 1.0 + DL & UL scheduling timing : 5.0 + UL Indication : 1.0 + Slot Indication : 6.0 DeviationThreshold : feprx : 0.25 feptx_prec : 0.25 diff --git a/ci-scripts/datalog_rt_stats.60.2x2.yaml b/ci-scripts/datalog_rt_stats.60.2x2.yaml index a196695c4b..064d6374c1 100644 --- a/ci-scripts/datalog_rt_stats.60.2x2.yaml +++ b/ci-scripts/datalog_rt_stats.60.2x2.yaml @@ -15,10 +15,10 @@ Ref : DLSCH encoding : 155.0 L1 Rx processing : 345.0 PUSCH inner-receiver : 155.0 - Schedule Response : 3.0 - DL & UL scheduling timing : 13.0 + Schedule Response : 1.0 + DL & UL scheduling timing : 8.0 UL Indication : 3.0 - Slot Indication : 12.0 + Slot Indication : 9.0 DeviationThreshold : feprx : 0.25 feptx_prec : 0.25 diff --git a/ci-scripts/datalog_rt_stats.default.yaml b/ci-scripts/datalog_rt_stats.default.yaml index 045768829c..17e45cf367 100644 --- a/ci-scripts/datalog_rt_stats.default.yaml +++ b/ci-scripts/datalog_rt_stats.default.yaml @@ -15,10 +15,10 @@ Ref : DLSCH encoding : 100.0 L1 Rx processing : 290.0 PUSCH inner-receiver : 115.0 - Schedule Response : 3.0 - DL & UL scheduling timing : 6.0 + Schedule Response : 1.0 + DL & UL scheduling timing : 4.0 UL Indication : 2.0 - Slot Indication : 7.0 + Slot Indication : 5.0 DeviationThreshold : feprx : 0.25 feptx_prec : 0.25 diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index bea421a995..fff1423c16 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -47,7 +47,7 @@ static int get_single_ue_rnti_mac(void) { NR_UE_info_t *ue = NULL; - UE_iterator(RC.nrmac[0]->UE_info.list, it) { + UE_iterator(RC.nrmac[0]->UE_info.connected_ue_list, it) { if (it && ue) return -1; if (it) diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c index dc48a477d3..7136f5a1b7 100644 --- a/common/utils/telnetsrv/telnetsrv_o1.c +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -123,7 +123,7 @@ static int get_stats(char *buf, int debug, telnet_printfunc_t prnt) static b_t last_total[MAX_MOBILES_PER_GNB] = {0}; // TODO: hash table? ue_stat_t ue_stat[MAX_MOBILES_PER_GNB] = {0}; int num_ues = 0; - UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) { + UE_iterator((NR_UE_info_t **)mac->UE_info.connected_ue_list, it) { nr_rlc_statistics_t rlc = {0}; nr_rlc_get_statistics(it->rnti, srb_flag, rb_id, &rlc); b_t *lt = &last_total[num_ues]; @@ -369,7 +369,7 @@ static int stop_modem(char *buf, int debug, telnet_printfunc_t prnt) * scheduler, which has many PUCCH structures filled with expected frame/slot * combinations that won't happen. */ const gNB_MAC_INST *mac = RC.nrmac[0]; - UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) { + UE_iterator((NR_UE_info_t **)mac->UE_info.connected_ue_list, it) { nr_mac_trigger_ul_failure(&it->UE_sched_ctrl, 1); } usleep(50000); diff --git a/doc/Doxyfile b/doc/Doxyfile index 6399f7107c..a154051692 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1844,12 +1844,10 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/rrc_defs.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/L2_interface_ue.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_internode.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_defs.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_if.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_direct.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_config.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_GTPV1U.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl_direct.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_radio_bearers.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_NGAP.h \ @@ -1862,10 +1860,8 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_config.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_radio_bearers.h \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_reconfig.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_NGAP.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl_f1ap.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_GTPV1U.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_nsa.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/LTE/rrc_eNB_GTPV1U.c \ diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 5a8464b60c..b9302392ab 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -305,11 +305,6 @@ static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cf } if (gnb_nb > 0) { - if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) { - LOG_E(GNB_APP, "Create task for gNB APP failed\n"); - return -1; - } - if (!NODE_IS_DU(node_type)) { if (itti_create_task (TASK_RRC_GNB, rrc_gnb_task, NULL) < 0) { LOG_E(NR_RRC, "Create task for NR RRC gNB failed\n"); @@ -333,6 +328,11 @@ static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cf itti_free(TASK_UNKNOWN, msg); } + if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) { + LOG_E(GNB_APP, "Create task for gNB APP failed\n"); + return -1; + } + //Use check on x2ap to consider the NSA scenario if((is_x2ap_enabled() || IS_SA_MODE(get_softmodem_params())) && (node_type != ngran_gNB_CUCP)) { if (itti_create_task (TASK_GTPV1_U, >pv1uTask, NULL) < 0) { diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index f767734e5f..8babb7598d 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -184,8 +184,8 @@ int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1, g_nrOfLay void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, slot_t slot) { - NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.list[0]; - AssertFatal(RC.nrmac[module_id]->UE_info.list[1]==NULL, "can have only a single UE\n"); + NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.connected_ue_list[0]; + AssertFatal(RC.nrmac[module_id]->UE_info.connected_ue_list[1] == NULL, "Only single UE allowed in dlsim\n"); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl; NR_UE_DL_BWP_t *current_BWP = &UE_info->current_DL_BWP; NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon; @@ -780,8 +780,10 @@ printf("%d\n", slot); NR_UE_NR_Capability_t *UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t)); prepare_sim_uecap(UE_Capability_nr, scc, mu, N_RB_DL, g_mcsTableIdx, 0); - - NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, 0); + rnti_t rnti = 0x1234; + int uid = 0; + NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, uid); + secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc); /* -U option modify DMRS */ if(modify_dmrs) { @@ -796,15 +798,15 @@ printf("%d\n", slot); //xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup); // UE dedicated configuration - nr_mac_add_test_ue(RC.nrmac[0], secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity, secondaryCellGroup); + nr_mac_add_test_ue(RC.nrmac[0], rnti, secondaryCellGroup); // reset preprocessor to the one of DLSIM after it has been set during // nr_mac_config_scc() gNB_mac->pre_processor_dl = nr_dlsim_preprocessor; phy_init_nr_gNB(gNB); N_RB_DL = gNB->frame_parms.N_RB_DL; - NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.list[0]; + NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.connected_ue_list[0]; - configure_UE_BWP(RC.nrmac[0], scc, &UE_info->UE_sched_ctrl, NULL, UE_info, -1, -1); + configure_UE_BWP(RC.nrmac[0], scc, UE_info, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1); // stub to configure frame_parms // nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index a23320ee10..83c1c31826 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -672,15 +672,16 @@ int main(int argc, char *argv[]) fix_scd(scd); NR_UE_NR_Capability_t* UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t)); - prepare_sim_uecap(UE_Capability_nr,scc,mu, - N_RB_UL,0,mcs_table); - - NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, 0); + prepare_sim_uecap(UE_Capability_nr, scc, mu, N_RB_UL, 0, mcs_table); + rnti_t rnti = 0x1234; + int uid = 0; + NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, uid); + secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc); NR_BCCH_BCH_Message_t *mib = get_new_MIB_NR(scc); // UE dedicated configuration - nr_mac_add_test_ue(RC.nrmac[0], secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity, secondaryCellGroup); + nr_mac_add_test_ue(RC.nrmac[0], rnti, secondaryCellGroup); frame_parms->nb_antennas_tx = 1; frame_parms->nb_antennas_rx = n_rx; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c index 854ef57d15..5a451cff01 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c @@ -37,7 +37,7 @@ bool read_mac_sm(void* data) NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info; size_t num_ues = 0; - UE_iterator(UE_info->list, ue) { + UE_iterator(UE_info->connected_ue_list, ue) { if (ue) num_ues += 1; } @@ -49,7 +49,7 @@ bool read_mac_sm(void* data) } size_t i = 0; //TODO - UE_iterator(UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { const NR_UE_sched_ctrl_t* sched_ctrl = &UE->UE_sched_ctrl; mac_ue_stats_impl_t* rd = &mac->msg.ue_stats[i]; diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.c index 08b070eb8d..d98fe35e88 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_rlc.c @@ -38,7 +38,7 @@ uint32_t num_act_rb(NR_UEs_t* const UE_info) assert(UE_info!= NULL); uint32_t act_rb = 0; - UE_iterator(UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { uint16_t const rnti = UE->rnti; for(int rb_id = 1; rb_id < 6; ++rb_id ){ nr_rlc_statistics_t rlc = {0}; @@ -55,7 +55,7 @@ void active_avg_to_tx(NR_UEs_t* const UE_info) { assert(UE_info!= NULL); - UE_iterator(UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { uint16_t const rnti = UE->rnti; for(int rb_id = 1; rb_id < 6; ++rb_id ){ nr_rlc_statistics_t rlc = {0}; @@ -91,7 +91,7 @@ bool read_rlc_sm(void* data) rlc->msg.tstamp = time_now_us(); uint32_t i = 0; - UE_iterator(UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { uint16_t const rnti = UE->rnti; //for every LC ID for(int rb_id = 1; rb_id < 6; ++rb_id ){ diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c index c9620e871f..aaf46797ac 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -282,7 +282,7 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst const ngran_node_t node_type = get_e2_node_type(); // Take MAC info - UE_iterator (RC.nrmac[0]->UE_info.list, ue) { + UE_iterator(RC.nrmac[0]->UE_info.connected_ue_list, ue) { NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl; // UE matches if any of its DRBs matches for (size_t l = 0; l < seq_arr_size(&sched_ctrl->lc_config); ++l) { 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/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 22d9ed6f8a..281bda44ef 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2136,7 +2136,8 @@ gNB_RRC_INST *RCconfig_NRRRC() openair_rrc_gNB_configuration(rrc, &nrrrc_config); }//End if (num_gnbs>0) - config_security(rrc); + if (!NODE_IS_DU(rrc->node_type)) + config_security(rrc); return rrc; } diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 90891919db..6f41db3764 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -858,14 +858,6 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c find_SSB_and_RO_available(nrmac); - NR_COMMON_channels_t *cc = &nrmac->common_channels[0]; - NR_SCHED_LOCK(&nrmac->sched_lock); - for (int n = 0; n < NR_NB_RA_PROC_MAX; n++) { - NR_RA_t *ra = &cc->ra[n]; - nr_clear_ra_proc(ra); - } - NR_SCHED_UNLOCK(&nrmac->sched_lock); - if (IS_SA_MODE(get_softmodem_params())) config_sched_ctrlCommon(nrmac); } @@ -979,18 +971,18 @@ bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t DevAssert(get_softmodem_params()->phy_test); NR_SCHED_LOCK(&nrmac->sched_lock); - NR_UE_info_t *UE = add_new_nr_ue(nrmac, rnti, CellGroup); - if (!UE) { + NR_UE_info_t *UE = get_new_nr_ue_inst(&nrmac->UE_info.uid_allocator, rnti, CellGroup); + DevAssert(UE != NULL); // test-mode: we assume we can always create a UE + free_and_zero(UE->ra); // test-mode (sims, phy-test): UE will not do RA + bool res = add_connected_nr_ue(nrmac, UE); + if (!res) { LOG_E(NR_MAC, "Error adding UE %04x\n", rnti); + delete_nr_ue_data(UE, NULL, &nrmac->UE_info.uid_allocator); NR_SCHED_UNLOCK(&nrmac->sched_lock); return false; } - - if (CellGroup->spCellConfig && CellGroup->spCellConfig->reconfigurationWithSync - && CellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated - && CellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra) { - nr_mac_prepare_ra_ue(RC.nrmac[0], UE->rnti, CellGroup); - } + int ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific; + configure_UE_BWP(nrmac, nrmac->common_channels[0].ServingCellConfigCommon, UE, false, ss_type, -1, -1); process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, CellGroup->rlc_BearerToAddModList); AssertFatal(CellGroup->rlc_BearerToReleaseList == NULL, "cannot release bearers while adding new UEs\n"); NR_SCHED_UNLOCK(&nrmac->sched_lock); @@ -998,32 +990,18 @@ bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t return true; } -bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup) +void nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, NR_UE_info_t *UE) { DevAssert(nrmac != NULL); - DevAssert(CellGroup != NULL); NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock); - - // NSA case: need to pre-configure CFRA - const int CC_id = 0; - NR_COMMON_channels_t *cc = &nrmac->common_channels[CC_id]; - uint8_t ra_index = 0; - /* checking for free RA process */ - for(; ra_index < NR_NB_RA_PROC_MAX; ra_index++) { - if ((cc->ra[ra_index].ra_state == nrRA_gNB_IDLE) && (!cc->ra[ra_index].cfra)) - break; - } - if (ra_index == NR_NB_RA_PROC_MAX) { - LOG_E(NR_MAC, "RA processes are not available for CFRA RNTI %04x\n", rnti); - return false; - } - NR_RA_t *ra = &cc->ra[ra_index]; + NR_RA_t *ra = UE->ra; ra->cfra = true; - ra->rnti = rnti; - ra->CellGroup = CellGroup; + NR_CellGroupConfig_t *CellGroup = UE->CellGroup; + DevAssert(CellGroup != NULL); struct NR_CFRA *cfra = CellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra; uint8_t num_preamble = cfra->resources.choice.ssb->ssb_ResourceList.list.count; ra->preambles.num_preambles = num_preamble; + NR_COMMON_channels_t *cc = &nrmac->common_channels[0]; for (int i = 0; i < cc->num_active_ssb; i++) { for (int j = 0; j < num_preamble; j++) { if (cc->ssb_index[i] == cfra->resources.choice.ssb->ssb_ResourceList.list.array[j]->ssb) { @@ -1033,27 +1011,5 @@ bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig } } } - LOG_I(NR_MAC, "Added new %s process for UE RNTI %04x with initial CellGroup\n", ra->cfra ? "CFRA" : "CBRA", rnti); - return true; -} - -/* Prepare a new CellGroupConfig to be applied for this UE. We cannot - * immediatly apply it, as we have to wait for the reconfiguration through RRC. - * This function sets up everything to apply the reconfiguration. Later, we - * will trigger the UE inactivity with nr_mac_interrupt_ue_transmission(); upon - * expiry, nr_mac_apply_cellgroup() will apply the CellGroupConfig (radio - * config etc). */ -bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup) -{ - DevAssert(nrmac != NULL); - DevAssert(UE != NULL); - DevAssert(CellGroup != NULL); - - /* we assume that this function is mutex-protected from outside */ - NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock); - - UE->reconfigCellGroup = CellGroup; - UE->expect_reconfiguration = true; - - return true; + LOG_I(NR_MAC, "Added new %s process for UE RNTI %04x with initial CellGroup\n", ra->cfra ? "CFRA" : "CBRA", UE->rnti); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 808afc8d86..edddd535b0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -49,14 +49,14 @@ // forward declaration of functions used in this file static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, NR_ServingCellConfigCommon_t *scc, - const NR_RA_t *ra, + NR_UE_info_t *UE, int startSymbolAndLength, int scs, int bwp_size, int bwp_start, int mappingtype, int fh); -static void nr_fill_rar(uint8_t Mod_idP, NR_RA_t *ra, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu); +static void nr_fill_rar(uint8_t Mod_idP, NR_UE_info_t *UE, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu); static const uint8_t DELTA[4] = {2, 3, 4, 6}; @@ -278,7 +278,7 @@ static void schedule_nr_MsgA_pusch(NR_UplinkConfigCommon_t *uplinkConfigCommon, pusch_pdu->nr_of_symbols = L; pusch_pdu->pusch_data.new_data_indicator = 1; pusch_pdu->nrOfLayers = 1; - pusch_pdu->num_dmrs_cdm_grps_no_data = 2; // no data in dmrs symbols as in 6.2.2 in 38.214 + pusch_pdu->num_dmrs_cdm_grps_no_data = L <= 2 ? 1 : 2; // no data in dmrs symbols as in 6.2.2 in 38.214 pusch_pdu->ul_dmrs_symb_pos = get_l_prime(3, 0, pusch_dmrs_pos2, pusch_len1, 10, dmrs_TypeA_Position); pusch_pdu->transform_precoding = *uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_TransformPrecoder_r16; pusch_pdu->rb_bitmap[0] = 0; @@ -522,7 +522,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) } if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) { - if (gNB->UE_info.list[0] == NULL) + if (gNB->UE_info.connected_ue_list[0] == NULL) schedule_nr_MsgA_pusch(scc->uplinkConfigCommon, gNB, module_idP, @@ -636,39 +636,26 @@ int nr_fill_successrar(const NR_UE_sched_ctrl_t *ue_sched_ctl, return mac_pdu_length; } -static bool ra_contains_preamble(const NR_RA_t *ra, uint16_t preamble_index) +/** @brief find UE with RA process for given preamble */ +static NR_UE_info_t *get_existing_ra(gNB_MAC_INST *nr_mac, uint16_t preamble_index) { - for (int j = 0; j < ra->preambles.num_preambles; j++) { - // check if the preamble received correspond to one of the listed or configured preambles - if (preamble_index == ra->preambles.preamble_list[j]) { - if (ra->rnti == 0 && get_softmodem_params()->nsa) - continue; - return true; + UE_iterator(nr_mac->UE_info.access_ue_list, UE) { + NR_RA_t *ra = UE->ra; + for (int i = 0; i < ra->preambles.num_preambles; ++i) { + if (ra->preambles.preamble_list[i] == preamble_index) + return UE; } } - return false; + return NULL; } -static NR_RA_t *find_free_nr_RA(NR_RA_t *ra_base, int ra_count, uint16_t preamble_index) +/** @brief add UE to list of UEs doing RA. + * + * Remove with nr_release_ra_UE(). */ +bool add_new_UE_RA(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) { - // for posteriority: in the past we checked the beam index, but only in CFRA - //if (ra->cfra && preamble_index != ra->preamble.preamble_list[beam_index]]) - // // then is not right RA - // - // that seems strange because: - // - we check preamble_index already - // - why only CFRA? - - for (int i = 0; i < ra_count; ++i) { - NR_RA_t *ra = &ra_base[i]; - if (ra->ra_state != nrRA_gNB_IDLE) - continue; - if (!ra_contains_preamble(ra, preamble_index)) - continue; - - return ra; - } - return NULL; + DevAssert(UE->ra); // a UE in the acess_ue_list needs to have an RA process + return add_UE_to_list(NR_NB_RA_PROC_MAX, nr_mac->UE_info.access_ue_list, UE); } static uint8_t nr_get_msg3_tpc(uint32_t preamble_power) @@ -681,10 +668,31 @@ static uint8_t nr_get_msg3_tpc(uint32_t preamble_power) return 3; // it means 0dB } +static unsigned int get_slot_RA(const NR_ServingCellConfigCommon_t *scc, + const NR_RACH_ConfigCommon_t *rach_ConfigCommon, + const NR_MsgA_ConfigCommon_r16_t *msgacc, + frame_type_t frame_type, + int slot) +{ + uint8_t index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; + uint16_t prach_format = + get_nr_prach_format_from_index(index, scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, frame_type); + unsigned int slot_RA; + if ((prach_format & 0xff) < 4) { + const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; + const int mu = nr_get_prach_or_ul_mu(msgacc, rach_ConfigCommon, ul_mu); + unsigned int slots_per_sf = (1 << mu); + slot_RA = slot / slots_per_sf; + } else { + slot_RA = slot; + } + return slot_RA; +} + void nr_initiate_ra_proc(module_id_t module_idP, int CC_id, - frame_t frameP, - int slotP, + frame_t frame, + int slot, uint16_t preamble_index, uint8_t freq_index, uint8_t symbol, @@ -696,76 +704,76 @@ void nr_initiate_ra_proc(module_id_t module_idP, gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_SCHED_LOCK(&nr_mac->sched_lock); - NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; - - NR_RA_t *ra = find_free_nr_RA(cc->ra, sizeofArray(cc->ra), preamble_index); - if (ra == NULL) { - LOG_E(NR_MAC, "FAILURE: %4d.%2d initiating RA procedure for preamble index %d: no free RA process\n", frameP, slotP, preamble_index); + /* check if preamble exists (NSA, HO cases) */ + NR_UE_info_t *UE = get_existing_ra(nr_mac, preamble_index); + if ((get_softmodem_params()->nsa || get_softmodem_params()->do_ra) && !UE) { + /* we are in NSA, but no UE has been configured => we ignore it */ + LOG_W(NR_MAC, "random access with preamble %d: no pre-configured RA process found\n", preamble_index); NR_SCHED_UNLOCK(&nr_mac->sched_lock); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0); return; } - if (ra->rnti == 0) { // This condition allows for the usage of a preconfigured rnti for the CFRA - bool rnti_found = nr_mac_get_new_rnti(&nr_mac->UE_info, cc->ra, sizeofArray(cc->ra), &ra->rnti); + if (!UE) { + /* in CBRA: we don't know this UE yet. There might be CFRA (e.g., HO IN SA) + * where we know the UE */ + rnti_t rnti; + bool rnti_found = nr_mac_get_new_rnti(&nr_mac->UE_info, &rnti); if (!rnti_found) { LOG_E(NR_MAC, "initialisation random access: no more available RNTIs for new UE\n"); - nr_clear_ra_proc(ra); + NR_SCHED_UNLOCK(&nr_mac->sched_lock); + return; + } + + UE = get_new_nr_ue_inst(&nr_mac->UE_info.uid_allocator, rnti, NULL); + if (!UE) { + LOG_E(NR_MAC, "FAILURE: %4d.%2d cannot create UE context, ignoring RA because RRC Reject not implemented yet\n", frame, slot); + NR_SCHED_UNLOCK(&nr_mac->sched_lock); + return; + } + if (!add_new_UE_RA(nr_mac, UE)) { + LOG_E(NR_MAC, "FAILURE: %4d.%2d initiating RA procedure for preamble index %d: no free RA process\n", frame, slot, preamble_index); + delete_nr_ue_data(UE, NULL, &nr_mac->UE_info.uid_allocator); NR_SCHED_UNLOCK(&nr_mac->sched_lock); return; } } - ra->preamble_frame = frameP; - ra->preamble_slot = slotP; + NR_RA_t *ra = UE->ra; + ra->preamble_frame = frame; + ra->preamble_slot = slot; ra->preamble_index = preamble_index; ra->timing_offset = timing_offset; ra->msg3_TPC = nr_get_msg3_tpc(preamble_power); + NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - { - // 3GPP TS 38.321 Section 5.1.3(a) says t_id for RA-RNTI depends on mu as specified in clause 5.3.2 in TS 38.211 - // so mu = 0 for prach format < 4. - NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; - NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; - if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) - msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; - const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; - const int mu = nr_get_prach_or_ul_mu(msgacc, rach_ConfigCommon, ul_mu); - uint8_t index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; - uint16_t prach_format = - get_nr_prach_format_from_index(index, scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, cc->frame_type); - unsigned int slot_RA; - if ((prach_format & 0xff) < 4) { - unsigned int slots_per_sf = (1 << mu); - slot_RA = slotP / slots_per_sf; - } else { - slot_RA = slotP; - } - uint8_t ul_carrier_id = 0; // 0 for NUL 1 for SUL - ra->RA_rnti = nr_get_ra_rnti(symbol, slot_RA, freq_index, ul_carrier_id); - if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) { - ra->ra_type = RA_2_STEP; - ra->ra_state = nrRA_WAIT_MsgA_PUSCH; - ra->MsgB_rnti = nr_get_MsgB_rnti(symbol, slot_RA, freq_index, ul_carrier_id); - } else { - ra->ra_type = RA_4_STEP; - ra->ra_state = nrRA_Msg2; - } + // 3GPP TS 38.321 Section 5.1.3(a) says t_id for RA-RNTI depends on mu as specified in clause 5.3.2 in TS 38.211 + // so mu = 0 for prach format < 4. + NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; + NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; + if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) + msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; + uint8_t ul_carrier_id = 0; // 0 for NUL 1 for SUL + uint32_t slot_RA = get_slot_RA(scc, rach_ConfigCommon, msgacc, cc->frame_type, slot); + ra->RA_rnti = nr_get_ra_rnti(symbol, slot_RA, freq_index, ul_carrier_id); + if (msgacc) { + ra->ra_type = RA_2_STEP; + ra->ra_state = nrRA_WAIT_MsgA_PUSCH; + ra->MsgB_rnti = nr_get_MsgB_rnti(symbol, slot_RA, freq_index, ul_carrier_id); + } else { + ra->ra_type = RA_4_STEP; + ra->ra_state = nrRA_Msg2; } - int index = ra - cc->ra; - LOG_A(NR_MAC, "%d.%d UE RA-RNTI %04x TC-RNTI %04x: Activating RA process index %d\n", frameP, slotP, ra->RA_rnti, ra->rnti, index); + LOG_A(NR_MAC, "%d.%d UE RA-RNTI %04x TC-RNTI %04x: initiating RA procedure\n", frame, slot, ra->RA_rnti, UE->rnti); // Configure RA BWP - configure_UE_BWP(nr_mac, scc, NULL, ra, NULL, -1, -1); - + configure_UE_BWP(nr_mac, scc, UE, true, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); // return current SSB order in the list of tranmitted SSBs - int n_ssb = ssb_index_from_prach(module_idP, frameP, slotP, preamble_index, freq_index, symbol); - ra->beam_id = get_fapi_beamforming_index(nr_mac, cc->ssb_index[n_ssb]); + int n_ssb = ssb_index_from_prach(module_idP, frame, slot, preamble_index, freq_index, symbol); + UE->UE_beam_index = get_fapi_beamforming_index(nr_mac, cc->ssb_index[n_ssb]); NR_SCHED_UNLOCK(&nr_mac->sched_lock); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0); } @@ -788,14 +796,15 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t frame, slot_t slot, - NR_RA_t *ra, + NR_UE_info_t *UE, nfapi_nr_ul_dci_request_t *ul_dci_req) { gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; + NR_RA_t *ra = UE->ra; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; - NR_UE_ServingCell_Info_t *sc_info = &ra->sc_info; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info; NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp->tdaList_Common; int mu = ul_bwp->scs; @@ -805,12 +814,12 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, const int sched_slot = (slot + K2) % slots_frame; if (is_ul_slot(sched_slot, &nr_mac->frame_structure)) { - NR_beam_alloc_t beam_ul = beam_allocation_procedure(&nr_mac->beam_info, sched_frame, sched_slot, ra->beam_id, slots_frame); + NR_beam_alloc_t beam_ul = beam_allocation_procedure(&nr_mac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_frame); if (beam_ul.idx < 0) return; - NR_beam_alloc_t beam_dci = beam_allocation_procedure(&nr_mac->beam_info, frame, slot, ra->beam_id, slots_frame); + NR_beam_alloc_t beam_dci = beam_allocation_procedure(&nr_mac->beam_info, frame, slot, UE->UE_beam_index, slots_frame); if (beam_dci.idx < 0) { - reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, ra->beam_id, slots_frame, beam_ul.new_beam); + reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_frame, beam_ul.new_beam); return; } int fh = 0; @@ -841,7 +850,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, "%4d%2d: RA RNTI %04x CC_id %d Scheduling retransmission of Msg3 in (%d,%d)\n", frame, slot, - ra->rnti, + UE->rnti, CC_id, sched_frame, sched_slot); @@ -863,12 +872,12 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu; memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); - fill_msg3_pusch_pdu(pusch_pdu, scc, ra, startSymbolAndLength, mu, BWPSize, BWPStart, mappingtype, fh); + fill_msg3_pusch_pdu(pusch_pdu, scc, UE, startSymbolAndLength, mu, BWPSize, BWPStart, mappingtype, fh); future_ul_tti_req->n_pdus += 1; // generation of DCI 0_0 to schedule msg3 retransmission - NR_SearchSpace_t *ss = ra->ra_ss; - NR_ControlResourceSet_t *coreset = ra->coreset; + NR_SearchSpace_t *ss = UE->UE_sched_ctrl.search_space; + NR_ControlResourceSet_t *coreset = UE->UE_sched_ctrl.coreset; AssertFatal(coreset, "Coreset cannot be null for RA-Msg3 retransmission\n"); const int coresetid = coreset->controlResourceSetId; @@ -880,7 +889,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, &UE->UE_sched_ctrl.sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -891,18 +900,18 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, beam_dci.idx, ss, coreset, - &ra->sched_pdcch, + &UE->UE_sched_ctrl.sched_pdcch, true, 0); if (CCEIndex < 0) { - LOG_E(NR_MAC, "UE %04x cannot find free CCE!\n", ra->rnti); + LOG_E(NR_MAC, "UE %04x cannot find free CCE!\n", UE->rnti); return; } // Fill PDCCH DL DCI PDU nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; pdcch_pdu_rel15->numDlDci++; - dci_pdu->RNTI = ra->rnti; + dci_pdu->RNTI = UE->rnti; dci_pdu->ScramblingId = *scc->physCellId; dci_pdu->ScramblingRNTI = 0; dci_pdu->AggregationLevel = aggregation_level; @@ -914,7 +923,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, dci_pdu->precodingAndBeamforming.prg_size = 0; dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = ra->beam_id; + dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; dci_pdu_rel15_t uldci_payload={0}; @@ -932,7 +941,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, ra->msg3_TPC = 1; fill_dci_pdu_rel15(sc_info, - &ra->DL_BWP, + &UE->current_DL_BWP, ul_bwp, dci_pdu, &uldci_payload, @@ -948,7 +957,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, fill_pdcch_vrb_map(nr_mac, CC_id, - &ra->sched_pdcch, + &UE->UE_sched_ctrl.sched_pdcch, CCEIndex, aggregation_level, beam_dci.idx); @@ -963,7 +972,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, ra, scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer, K2, - ra->UL_BWP.scs); + ul_bwp->scs); // reset state to wait msg3 ra->ra_state = nrRA_WAIT_Msg3; @@ -979,6 +988,7 @@ static bool get_feasible_msg3_tda(const NR_ServingCellConfigCommon_t *scc, int slot, NR_RA_t *ra, NR_beam_info_t *beam_info, + int ue_beam_idx, const frame_structure_t *fs) { DevAssert(tda_list != NULL); @@ -1017,7 +1027,7 @@ static bool get_feasible_msg3_tda(const NR_ServingCellConfigCommon_t *scc, continue; // check if it is possible to allocate MSG3 in a beam in this slot - NR_beam_alloc_t beam = beam_allocation_procedure(beam_info, temp_frame, temp_slot, ra->beam_id, slots_per_frame); + NR_beam_alloc_t beam = beam_allocation_procedure(beam_info, temp_frame, temp_slot, ue_beam_idx, slots_per_frame); if (beam.idx < 0) continue; @@ -1032,14 +1042,15 @@ static bool get_feasible_msg3_tda(const NR_ServingCellConfigCommon_t *scc, return false; } -static bool nr_get_Msg3alloc(gNB_MAC_INST *mac, int CC_id, int current_slot, frame_t current_frame, NR_RA_t *ra) +static bool nr_get_Msg3alloc(gNB_MAC_INST *mac, int CC_id, int current_slot, frame_t current_frame, NR_UE_info_t *UE) { + NR_RA_t *ra = UE->ra; DevAssert(ra->Msg3_tda_id >= 0 && ra->Msg3_tda_id < 16); uint16_t msg3_nb_rb = 8; // sdu has 6 or 8 bytes - NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; - NR_UE_ServingCell_Info_t *sc_info = &ra->sc_info; + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info; const NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp->tdaList_Common; @@ -1048,7 +1059,7 @@ static bool nr_get_Msg3alloc(gNB_MAC_INST *mac, int CC_id, int current_slot, fra LOG_I(NR_MAC, "UE %04x: Msg3 scheduled at %d.%d (%d.%d TDA %u)\n", - ra->rnti, + UE->rnti, ra->Msg3_frame, ra->Msg3_slot, current_frame, @@ -1093,7 +1104,7 @@ static bool nr_get_Msg3alloc(gNB_MAC_INST *mac, int CC_id, int current_slot, fra static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, NR_ServingCellConfigCommon_t *scc, - const NR_RA_t *ra, + NR_UE_info_t *UE, int startSymbolAndLength, int scs, int bwp_size, @@ -1102,12 +1113,11 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, int fh) { int start_symbol_index,nr_of_symbols; - SLIV2SL(startSymbolAndLength, &start_symbol_index, &nr_of_symbols); int mcsindex = -1; // init value - + const NR_RA_t *ra = UE->ra; pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; - pusch_pdu->rnti = ra->rnti; + pusch_pdu->rnti = UE->rnti; pusch_pdu->handle = 0; pusch_pdu->bwp_start = bwp_start; pusch_pdu->bwp_size = bwp_size; @@ -1132,7 +1142,7 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, pusch_pdu->pusch_identity = *scc->physCellId; //If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id. pusch_pdu->scid = 0; //DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]. Should match what is sent in DCI 0_1, otherwise set to 0. pusch_pdu->dmrs_ports = 1; // 6.2.2 in 38.214 only port 0 to be used - pusch_pdu->num_dmrs_cdm_grps_no_data = 2; // no data in dmrs symbols as in 6.2.2 in 38.214 + pusch_pdu->num_dmrs_cdm_grps_no_data = nr_of_symbols <= 2 ? 1 : 2; // no data in dmrs symbols as in 6.2.2 in 38.214 pusch_pdu->resource_alloc = 1; //type 1 memset(pusch_pdu->rb_bitmap, 0, sizeof(pusch_pdu->rb_bitmap)); pusch_pdu->rb_start = ra->msg3_first_rb; @@ -1161,7 +1171,7 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, pusch_pdu->beamforming.num_prgs = 0; pusch_pdu->beamforming.prg_size = 0; // bwp_size; pusch_pdu->beamforming.dig_bf_interface = 1; - pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = ra->beam_id; + pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; int num_dmrs_symb = 0; for(int i = start_symbol_index; i < start_symbol_index+nr_of_symbols; i++) @@ -1188,16 +1198,16 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, } } -static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_t slotP, NR_RA_t *ra, uint8_t *RAR_pdu) +static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_t slotP, NR_UE_info_t *UE, uint8_t *RAR_pdu) { gNB_MAC_INST *mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; - NR_UE_ServingCell_Info_t *sc_info = &ra->sc_info; - + NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info; + NR_RA_t *ra = UE->ra; if (ra->ra_state == nrRA_gNB_IDLE) { - LOG_W(NR_MAC,"RA is not active for RA %X. skipping msg3 scheduling\n", ra->rnti); + LOG_W(NR_MAC,"RA is not active for RA %X. skipping msg3 scheduling\n", UE->rnti); return; } @@ -1214,7 +1224,7 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ vrb_map_UL[i + ra->msg3_first_rb + ra->msg3_bwp_start] |= mask; } - LOG_D(NR_MAC, "UE %04x: %d.%d RA is active, Msg3 in (%d,%d)\n", ra->rnti, frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); + LOG_D(NR_MAC, "UE %04x: %d.%d RA is active, Msg3 in (%d,%d)\n", UE->rnti, frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); buffer_index = ul_buffer_index(ra->Msg3_frame, ra->Msg3_slot, slots_frame, mac->UL_tti_req_ahead_size); nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[CC_id][buffer_index]; AssertFatal(future_ul_tti_req->SFN == ra->Msg3_frame @@ -1236,7 +1246,7 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ LOG_D(NR_MAC, "UE %04x: %d.%d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d)\n", - ra->rnti, + UE->rnti, frameP, slotP, ra->Msg3_frame, @@ -1245,18 +1255,18 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ ra->msg3_first_rb, ra->msg3_round); - fill_msg3_pusch_pdu(pusch_pdu, scc, ra, startSymbolAndLength, ul_bwp->scs, ibwp_size, ra->msg3_bwp_start, mappingtype, fh); + fill_msg3_pusch_pdu(pusch_pdu, scc, UE, startSymbolAndLength, ul_bwp->scs, ibwp_size, ra->msg3_bwp_start, mappingtype, fh); future_ul_tti_req->n_pdus += 1; // calling function to fill rar message - nr_fill_rar(module_idP, ra, RAR_pdu, pusch_pdu); + nr_fill_rar(module_idP, UE, RAR_pdu, pusch_pdu); } -static bool check_msg2_monitoring(const NR_RA_t *ra, int slots_per_frame, int current_frame, int current_slot) +static bool check_msg2_monitoring(const NR_SearchSpace_t *ss, int slots_per_frame, int current_frame, int current_slot) { // check if the slot is not among the PDCCH monitored ones (38.213 10.1) int monitoring_slot_period, monitoring_offset; - get_monitoring_period_offset(ra->ra_ss, &monitoring_slot_period, &monitoring_offset); + get_monitoring_period_offset(ss, &monitoring_slot_period, &monitoring_offset); if ((current_frame * slots_per_frame + current_slot - monitoring_offset) % monitoring_slot_period != 0) return false; return true; @@ -1326,8 +1336,7 @@ static bool msg2_in_response_window(int rach_frame, } static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, - NR_RA_t *ra, - NR_UE_DL_BWP_t *dl_bwp, + NR_UE_info_t *UE, nfapi_nr_dl_tti_request_body_t *dl_req, NR_sched_pucch_t *pucch, NR_pdsch_dmrs_t dmrs_info, @@ -1354,7 +1363,8 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, { // look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it. This is especially // important if we have multiple RAs, and the DLSCH has to reuse them, so we need to mark them - NR_ControlResourceSet_t *coreset = ra->coreset; + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; const int coresetid = coreset->controlResourceSetId; nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = nr_mac->pdcch_pdu_idx[CC_id][coresetid]; if (!pdcch_pdu_rel15) { @@ -1364,7 +1374,7 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, &sched_ctrl->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -1377,7 +1387,7 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; int mcsTableIdx = dl_bwp->mcsTableIdx; pdsch_pdu_rel15->pduBitmap = 0; @@ -1412,14 +1422,14 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, pdsch_pdu_rel15->StartSymbolIndex = tda.startSymbolIndex; pdsch_pdu_rel15->NrOfSymbols = tda.nrOfSymbols; pdsch_pdu_rel15->dlDmrsSymbPos = dmrs_info.dl_dmrs_symb_pos; - pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, ra->sc_info.dl_bw_tbslbrm, 1); + pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, UE->sc_info.dl_bw_tbslbrm, 1); pdsch_pdu_rel15->maintenance_parms_v3.ldpcBaseGraph = get_BG(tb_size << 3, R); pdsch_pdu_rel15->precodingAndBeamforming.num_prgs = 1; pdsch_pdu_rel15->precodingAndBeamforming.prg_size = 275; pdsch_pdu_rel15->precodingAndBeamforming.dig_bf_interfaces = 1; pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = ra->beam_id; + pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; /* Fill PDCCH DL DCI PDU */ nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; @@ -1436,7 +1446,7 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, dci_pdu->precodingAndBeamforming.prg_size = 0; dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = ra->beam_id; + dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; dci_pdu_rel15_t dci_payload; dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu_rel15->rbSize, @@ -1482,15 +1492,15 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, pdcch_pdu_rel15->DurationSymbols, pdsch_pdu_rel15->BWPSize); - fill_dci_pdu_rel15(&ra->sc_info, + fill_dci_pdu_rel15(&UE->sc_info, dl_bwp, - &ra->UL_BWP, + &UE->current_UL_BWP, &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], &dci_payload, NR_DL_DCI_FORMAT_1_0, rnti_type, dl_bwp->bwp_id, - ra->ra_ss, + sched_ctrl->search_space, coreset, 0, // parameter not needed for DCI 1_0 nr_mac->cset0_bwp_size); @@ -1516,7 +1526,7 @@ static void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, slot_t slotP, - NR_RA_t *ra, + NR_UE_info_t *UE, nfapi_nr_dl_tti_request_t *DL_req, nfapi_nr_tx_data_request_t *TX_req) { @@ -1528,28 +1538,30 @@ static void nr_generate_Msg2(module_id_t module_idP, } NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; - NR_UE_DL_BWP_t *dl_bwp = &ra->DL_BWP; - NR_UE_ServingCell_Info_t *sc_info = &ra->sc_info; + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; + NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - + NR_RA_t *ra = UE->ra; long rrc_ra_ResponseWindow = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow; const int n_slots_frame = nr_mac->frame_structure.numb_slots_frame; if (!msg2_in_response_window(ra->preamble_frame, ra->preamble_slot, n_slots_frame, rrc_ra_ResponseWindow, frameP, slotP)) { - LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: exceeded RA window, cannot schedule Msg2\n", ra->RA_rnti, ra->rnti); - nr_clear_ra_proc(ra); + LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: exceeded RA window, cannot schedule Msg2\n", ra->RA_rnti, UE->rnti); + nr_release_ra_UE(nr_mac, UE->rnti); return; } - if (!check_msg2_monitoring(ra, n_slots_frame, frameP, slotP)) { - LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: Msg2 not monitored by UE\n", ra->RA_rnti, ra->rnti); + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_SearchSpace_t *ss = sched_ctrl->search_space; + if (!check_msg2_monitoring(ss, n_slots_frame, frameP, slotP)) { + LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: Msg2 not monitored by UE\n", ra->RA_rnti, UE->rnti); return; } - NR_beam_alloc_t beam = beam_allocation_procedure(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame); + NR_beam_alloc_t beam = beam_allocation_procedure(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame); if (beam.idx < 0) return; - const NR_UE_UL_BWP_t *ul_bwp = &ra->UL_BWP; + const NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; bool ret = get_feasible_msg3_tda(scc, DELTA[ul_bwp->scs], ul_bwp->tdaList_Common, @@ -1557,19 +1569,17 @@ static void nr_generate_Msg2(module_id_t module_idP, slotP, ra, &nr_mac->beam_info, + UE->UE_beam_index, &nr_mac->frame_structure); if (!ret || ra->Msg3_tda_id > 15) { - LOG_D(NR_MAC, "UE RNTI %04x %d.%d: infeasible Msg3 TDA\n", ra->rnti, frameP, slotP); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + LOG_D(NR_MAC, "UE RNTI %04x %d.%d: infeasible Msg3 TDA\n", UE->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } int mcsIndex = -1; // initialization value int rbStart = 0; int rbSize = 8; - - NR_SearchSpace_t *ss = ra->ra_ss; - long BWPStart = 0; long BWPSize = 0; NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; @@ -1577,12 +1587,12 @@ static void nr_generate_Msg2(module_id_t module_idP, BWPStart = dl_bwp->BWPStart; BWPSize = sc_info->initial_dl_BWPSize; } else { - type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[cc->ssb_index[ra->beam_id]]; + type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[cc->ssb_index[UE->UE_beam_index]]; BWPStart = type0_PDCCH_CSS_config->cset_start_rb; BWPSize = type0_PDCCH_CSS_config->num_rbs; } - NR_ControlResourceSet_t *coreset = ra->coreset; + NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; AssertFatal(coreset, "Coreset cannot be null for RA-Msg2\n"); const int coresetid = coreset->controlResourceSetId; // Calculate number of symbols @@ -1609,34 +1619,34 @@ static void nr_generate_Msg2(module_id_t module_idP, if (rbStart > (BWPSize - rbSize)) { LOG_W(NR_MAC, "Cannot find free vrb_map for RA RNTI %04x!\n", ra->RA_rnti); - reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, UE->UE_beam_index, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } // Checking if the DCI allocation is feasible in current subframe nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; if (dl_req->nPDUs > NFAPI_NR_MAX_DL_TTI_PDUS - 2) { - LOG_W(NR_MAC, "UE %04x: %d.%d FAPI DL structure is full\n", ra->rnti, frameP, slotP); - reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + LOG_W(NR_MAC, "UE %04x: %d.%d FAPI DL structure is full\n", UE->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, UE->UE_beam_index, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } uint8_t aggregation_level; - int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &ra->sched_pdcch, true, 0); + int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &sched_ctrl->sched_pdcch, true, 0); if (CCEIndex < 0) { - LOG_W(NR_MAC, "UE %04x: %d.%d cannot find free CCE for Msg2!\n", ra->rnti, frameP, slotP); - reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + LOG_W(NR_MAC, "UE %04x: %d.%d cannot find free CCE for Msg2!\n", UE->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, UE->UE_beam_index, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } - bool msg3_ret = nr_get_Msg3alloc(nr_mac, CC_id, slotP, frameP, ra); + bool msg3_ret = nr_get_Msg3alloc(nr_mac, CC_id, slotP, frameP, UE); if (!msg3_ret) { - reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, ra->beam_id, n_slots_frame, ra->Msg3_beam.new_beam); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, UE->UE_beam_index, n_slots_frame, ra->Msg3_beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } @@ -1645,14 +1655,14 @@ static void nr_generate_Msg2(module_id_t module_idP, // Distance calculation according to SCF222.10.02 RACH.indication (table 3-74) and 38.213 4.2/38.211 4.3.1 // T_c according to 38.211 4.1 float T_c_ns = 0.509; - int numerology = ra->UL_BWP.scs; + int numerology = ul_bwp->scs; float rtt_ns = T_c_ns * 16 * 64 / (1 << numerology) * ra->timing_offset; float speed_of_light_in_meters_per_second = 299792458.0f; float distance_in_meters = speed_of_light_in_meters_per_second * rtt_ns / 1000 / 1000 / 1000 / 2; LOG_A(NR_MAC, "UE %04x: %d.%d Generating RA-Msg2 DCI, RA RNTI 0x%x, state %d, preamble_index(RAPID) %d, " "timing_offset = %d (estimated distance %.1f [m])\n", - ra->rnti, + UE->rnti, frameP, slotP, ra->RA_rnti, @@ -1689,8 +1699,7 @@ static void nr_generate_Msg2(module_id_t module_idP, } prepare_dl_pdus(nr_mac, - ra, - dl_bwp, + UE, dl_req, NULL, dmrs_parms, @@ -1719,28 +1728,19 @@ static void nr_generate_Msg2(module_id_t module_idP, nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[TX_req->Number_of_PDUs]; // Program UL processing for Msg3 - nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *)&tx_req->TLVs[0].value.direct[0]); + nr_add_msg3(module_idP, CC_id, frameP, slotP, UE, (uint8_t *)&tx_req->TLVs[0].value.direct[0]); // Start RA contention resolution timer in Msg3 transmission slot (current slot + K2) // 3GPP TS 38.321 Section 5.1.5 Contention Resolution start_ra_contention_resolution_timer( ra, scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer, - *ra->UL_BWP.tdaList_Common->list.array[ra->Msg3_tda_id]->k2 + get_NTN_Koffset(scc), - ra->UL_BWP.scs); - - if (ra->cfra) { - NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_idP]->UE_info, ra->rnti); - if (UE) { - int delay = nr_mac_get_reconfig_delay_slots(ra->DL_BWP.scs); - interrupt_followup_action_t action = UE->reconfigCellGroup ? FOLLOW_INSYNC_RECONFIG : FOLLOW_INSYNC; - nr_mac_interrupt_ue_transmission(RC.nrmac[module_idP], UE, action, delay); - } - } + *ul_bwp->tdaList_Common->list.array[ra->Msg3_tda_id]->k2 + get_NTN_Koffset(scc), + ul_bwp->scs); LOG_D(NR_MAC, "UE %04x: %d.%d: Setting RA-Msg3 reception (%s) for SFN.Slot %d.%d\n", - ra->rnti, + UE->rnti, frameP, slotP, ra->cfra ? "CFRA" : "CBRA", @@ -1767,7 +1767,7 @@ static void nr_generate_Msg2(module_id_t module_idP, T_BUFFER(&tx_req->TLVs[0].value.direct[0], tx_req->TLVs[0].length)); // Mark the corresponding symbols RBs as used - fill_pdcch_vrb_map(nr_mac, CC_id, &ra->sched_pdcch, CCEIndex, aggregation_level, beam.idx); + fill_pdcch_vrb_map(nr_mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, aggregation_level, beam.idx); for (int rb = 0; rb < rbSize; rb++) { vrb_map[BWPStart + rb + rbStart] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); } @@ -1779,44 +1779,37 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, int CC_id, frame_t frameP, slot_t slotP, - NR_RA_t *ra, + NR_UE_info_t *UE, nfapi_nr_dl_tti_request_t *DL_req, nfapi_nr_tx_data_request_t *TX_req) { gNB_MAC_INST *nr_mac = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; - NR_UE_DL_BWP_t *dl_bwp = &ra->DL_BWP; + NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; // if it is a DL slot, if the RA is in MSG4 state if (is_dl_slot(slotP, &nr_mac->frame_structure)) { NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_SearchSpace_t *ss = ra->ra_ss; + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_SearchSpace_t *ss = sched_ctrl->search_space; + NR_RA_t *ra = UE->ra; const char *ra_type_str = ra->ra_type == RA_2_STEP ? "MsgB" : "Msg4"; - NR_ControlResourceSet_t *coreset = ra->coreset; + NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; AssertFatal(coreset != NULL, "Coreset cannot be null for RA %s\n", ra_type_str); uint16_t mac_sdu_length = 0; - - NR_UE_info_t *UE = find_nr_UE(&nr_mac->UE_info, ra->rnti); - if (!UE) { - LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table. Abort RA\n", ra_type_str, ra->rnti); - nr_clear_ra_proc(ra); - return; - } - - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; /* get the PID of a HARQ process awaiting retrnasmission, or -1 otherwise */ int current_harq_pid = sched_ctrl->retrans_dl_harq.head; logical_chan_id_t lcid = DL_SCH_LCID_CCCH; if (current_harq_pid < 0) { // Check for data on SRB0 (RRCSetup) - mac_rlc_status_resp_t srb_status = nr_mac_rlc_status_ind(ra->rnti, frameP, lcid); + mac_rlc_status_resp_t srb_status = nr_mac_rlc_status_ind(UE->rnti, frameP, lcid); if (srb_status.bytes_in_buffer == 0) { lcid = DL_SCH_LCID_DCCH; // Check for data on SRB1 (RRCReestablishment, RRCReconfiguration) - srb_status = nr_mac_rlc_status_ind(ra->rnti, frameP, lcid); + srb_status = nr_mac_rlc_status_ind(UE->rnti, frameP, lcid); } // Need to wait until data for Msg4 is ready @@ -1826,7 +1819,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } const int n_slots_frame = nr_mac->frame_structure.numb_slots_frame; - NR_beam_alloc_t beam = beam_allocation_procedure(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame); + NR_beam_alloc_t beam = beam_allocation_procedure(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame); if (beam.idx < 0) return; @@ -1837,7 +1830,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, BWPStart = dl_bwp->BWPStart; BWPSize = dl_bwp->BWPSize; } else { - type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[cc->ssb_index[ra->beam_id]]; + type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[cc->ssb_index[UE->UE_beam_index]]; BWPStart = type0_PDCCH_CSS_config->cset_start_rb; BWPSize = type0_PDCCH_CSS_config->num_rbs; } @@ -1850,21 +1843,21 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, beam.idx, ss, coreset, - &ra->sched_pdcch, + &sched_ctrl->sched_pdcch, true, 0); if (CCEIndex < 0) { - LOG_E(NR_MAC, "Cannot find free CCE for RA RNTI 0x%04x!\n", ra->rnti); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + LOG_E(NR_MAC, "Cannot find free CCE for RA RNTI 0x%04x!\n", UE->rnti); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } // Checking if the DCI allocation is feasible in current subframe nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; if (dl_req->nPDUs > NFAPI_NR_MAX_DL_TTI_PDUS - 2) { - LOG_I(NR_MAC, "UE %04x: %d.%d FAPI DL structure is full\n", ra->rnti, frameP, slotP); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + LOG_I(NR_MAC, "UE %04x: %d.%d FAPI DL structure is full\n", UE->rnti, frameP, slotP); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } @@ -1927,18 +1920,18 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } if (rbStart > (BWPSize - rbSize)) { - LOG_E(NR_MAC, "Cannot find free vrb_map for RNTI %04x!\n", ra->rnti); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + LOG_E(NR_MAC, "Cannot find free vrb_map for RNTI %04x!\n", UE->rnti); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } const int delta_PRI = 0; - int r_pucch = nr_get_pucch_resource(coreset, ra->UL_BWP.pucch_Config, CCEIndex); + int r_pucch = nr_get_pucch_resource(coreset, UE->current_UL_BWP.pucch_Config, CCEIndex); LOG_D(NR_MAC, "Msg4 r_pucch %d (CCEIndex %d, delta_PRI %d)\n", r_pucch, CCEIndex, delta_PRI); - int alloc = nr_acknack_scheduling(nr_mac, UE, frameP, slotP, ra->beam_id, r_pucch, 1); + int alloc = nr_acknack_scheduling(nr_mac, UE, frameP, slotP, UE->UE_beam_index, r_pucch, 1); if (alloc < 0) { LOG_D(NR_MAC,"Couldn't find a pucch allocation for ack nack (msg4) in frame %d slot %d\n", frameP, slotP); - reset_beam_status(&nr_mac->beam_info, frameP, slotP, ra->beam_id, n_slots_frame, beam.new_beam); + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } @@ -1966,10 +1959,10 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, uint16_t mac_pdu_length = 0; if (ra->ra_type == RA_4_STEP) { // UE Contention Resolution Identity MAC CE - mac_pdu_length = nr_write_ce_dlsch_pdu(module_idP, nr_mac->sched_ctrlCommon, buf, 255, ra->cont_res_id); + mac_pdu_length = nr_write_ce_dlsch_pdu(module_idP, sched_ctrl, buf, 255, ra->cont_res_id); } else if (ra->ra_type == RA_2_STEP) { - mac_pdu_length = nr_fill_successrar(nr_mac->sched_ctrlCommon, - ra->rnti, + mac_pdu_length = nr_fill_successrar(sched_ctrl, + UE->rnti, ra->cont_res_id, pucch->resource_indicator, pucch->timing_indicator, @@ -1982,7 +1975,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, uint8_t buffer[CCCH_SDU_SIZE]; uint8_t mac_subheader_len = sizeof(NR_MAC_SUBHEADER_SHORT); // Get RLC data on the SRB (RRCSetup, RRCReestablishment) - mac_sdu_length = nr_mac_rlc_data_req(module_idP, ra->rnti, true, lcid, CCCH_SDU_SIZE, (char *)buffer); + mac_sdu_length = nr_mac_rlc_data_req(module_idP, UE->rnti, true, lcid, CCCH_SDU_SIZE, (char *)buffer); if (mac_sdu_length < 256) { ((NR_MAC_SUBHEADER_SHORT *)&buf[mac_pdu_length])->R = 0; @@ -2001,12 +1994,11 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, memcpy(&buf[mac_pdu_length + mac_subheader_len], buffer, mac_sdu_length); } - rnti_t rnti = ra->ra_type == RA_4_STEP ? ra->rnti : ra->MsgB_rnti; + rnti_t rnti = ra->ra_type == RA_4_STEP ? UE->rnti : ra->MsgB_rnti; const int pduindex = nr_mac->pdu_index[CC_id]++; prepare_dl_pdus(nr_mac, - ra, - dl_bwp, + UE, dl_req, pucch, dmrs_info, @@ -2044,7 +2036,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } } - T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(ra->rnti), + T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(UE->rnti), T_INT(frameP), T_INT(slotP), T_INT(current_harq_pid), T_BUFFER(harq->transportBlock.buf, harq->tb_size)); // DL TX request @@ -2061,7 +2053,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, // Mark the corresponding symbols and RBs as used fill_pdcch_vrb_map(nr_mac, CC_id, - &ra->sched_pdcch, + &sched_ctrl->sched_pdcch, CCEIndex, aggregation_level, beam.idx); @@ -2072,7 +2064,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, ra->ra_state = nrRA_WAIT_Msg4_MsgB_ACK; LOG_I(NR_MAC, "UE %04x Generate %s: feedback at %4d.%2d, payload %d bytes, next state nrRA_WAIT_Msg4_MsgB_ACK\n", - ra->rnti, + UE->rnti, ra_type_str, pucch->frame, pucch->ul_slot, @@ -2080,67 +2072,39 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } } -static void nr_check_Msg4_MsgB_Ack(module_id_t module_id, int CC_id, frame_t frame, slot_t slot, NR_RA_t *ra) +void nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, NR_UE_info_t *UE, bool success) { + NR_RA_t *ra = UE->ra; const char *ra_type_str = ra->ra_type == RA_2_STEP ? "MsgB" : "Msg4"; - NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, ra->rnti); - if (!UE) { - LOG_E(NR_MAC, "Cannot check %s ACK/NACK, rnti %04x not in the table\n", ra_type_str, ra->rnti); - return; - } const int current_harq_pid = ra->harq_pid; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid]; - LOG_D(NR_MAC, "ue rnti 0x%04x, harq is waiting %d, round %d, frame %d %d, harq id %d\n", ra->rnti, harq->is_waiting, harq->round, frame, slot, current_harq_pid); + LOG_D(NR_MAC, "ue rnti 0x%04x, round %d, frame %d %d, harq id %d\n", UE->rnti, harq->round, frame, slot, current_harq_pid); - if (harq->is_waiting == 0) { - if (harq->round == 0) { - if (UE->Msg4_MsgB_ACKed) { - LOG_A(NR_MAC, - "%4d.%2d UE %04x: Received Ack of %s. CBRA procedure succeeded!\n", - frame, slot, ra->rnti, ra_type_str); - } else { - LOG_I(NR_MAC, - "%4d.%2d UE %04x: RA Procedure failed at %s!\n", - frame, slot, ra->rnti, ra_type_str); - nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs); - } - - // Pause scheduling according to: - // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs - // Msg4 may transmit a RRCReconfiguration, for example when UE sends RRCReestablishmentComplete and MAC CE for C-RNTI in Msg3. - // In that case, gNB will generate a RRCReconfiguration that will be transmitted in Msg4, so we need to apply CellGroup after the Ack, - // UE->reconfigCellGroup already set when processing RRCReestablishment message - int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs); - nr_mac_interrupt_ue_transmission(RC.nrmac[module_id], UE, UE->interrupt_action, delay); - - nr_clear_ra_proc(ra); - if (sched_ctrl->retrans_dl_harq.head >= 0) { - remove_nr_list(&sched_ctrl->retrans_dl_harq, current_harq_pid); - } + if (harq->round == 0) { + if (success) { + gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; + NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon; + // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration + configure_UE_BWP(nr_mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); + transition_ra_connected_nr_ue(nr_mac, UE); + LOG_A(NR_MAC, "%4d.%2d UE %04x: Received Ack of %s. CBRA procedure succeeded!\n", frame, slot, UE->rnti, ra_type_str); } else { - LOG_I(NR_MAC, "(UE %04x) Received Nack in %s, preparing retransmission!\n", ra->rnti, ra_type_str); - ra->ra_state = ra->ra_type == RA_4_STEP ? nrRA_Msg4 : nrRA_MsgB; + LOG_I(NR_MAC, "%4d.%2d UE %04x: RA Procedure failed at %s!\n", frame, slot, UE->rnti, ra_type_str); + nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs); } + + if (sched_ctrl->retrans_dl_harq.head >= 0) { + remove_nr_list(&sched_ctrl->retrans_dl_harq, current_harq_pid); + } + } else { + LOG_I(NR_MAC, "(UE %04x) Received Nack in %s, preparing retransmission!\n", UE->rnti, ra_type_str); + ra->ra_state = ra->ra_type == RA_4_STEP ? nrRA_Msg4 : nrRA_MsgB; } } -void nr_clear_ra_proc(NR_RA_t *ra) -{ - /* we assume that this function is mutex-protected from outside */ - NR_SCHED_ENSURE_LOCKED(&RC.nrmac[0]->sched_lock); - memset(ra, 0, sizeof(*ra)); - ra->ra_state = nrRA_gNB_IDLE; - if (IS_SA_MODE(get_softmodem_params())) { // in SA, prefill with allowed preambles - ra->preambles.num_preambles = MAX_NUM_NR_PRACH_PREAMBLES; - for (int i = 0; i < MAX_NUM_NR_PRACH_PREAMBLES; i++) - ra->preambles.preamble_list[i] = i; - } -} - - ///////////////////////////////////// // Random Access Response PDU // // TS 38.213 ch 8.2 // @@ -2171,9 +2135,15 @@ void nr_clear_ra_proc(NR_RA_t *ra) // - sending only 1 RAR subPDU // - UL Grant: hardcoded CSI, TPC, time alloc // - padding -static void nr_fill_rar(uint8_t Mod_idP, NR_RA_t *ra, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu) +static void nr_fill_rar(uint8_t Mod_idP, NR_UE_info_t *UE, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu) { - LOG_D(NR_MAC, "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u TA command %d \n", ra->Msg2_frame, ra-> Msg2_slot, ra->preamble_index, ra->timing_offset); + NR_RA_t *ra = UE->ra; + LOG_D(NR_MAC, + "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u TA command %d \n", + ra->Msg2_frame, + ra->Msg2_slot, + ra->preamble_index, + ra->timing_offset); NR_RA_HEADER_BI *rarbi = (NR_RA_HEADER_BI *) dlsch_buffer; NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) (dlsch_buffer + 1); NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 2); @@ -2204,8 +2174,8 @@ static void nr_fill_rar(uint8_t Mod_idP, NR_RA_t *ra, uint8_t *dlsch_buffer, nfa rar->TA2 = (uint8_t) (ra->timing_offset & 0x1f); // 5 LSBs of timing advance // TC-RNTI - rar->TCRNTI_1 = (uint8_t) (ra->rnti >> 8); // 8 MSBs of rnti - rar->TCRNTI_2 = (uint8_t) (ra->rnti & 0xff); // 8 LSBs of rnti + rar->TCRNTI_1 = (uint8_t) (UE->rnti >> 8); // 8 MSBs of rnti + rar->TCRNTI_2 = (uint8_t) (UE->rnti & 0xff); // 8 LSBs of rnti // UL grant @@ -2255,6 +2225,22 @@ static void nr_fill_rar(uint8_t Mod_idP, NR_RA_t *ra, uint8_t *dlsch_buffer, nfa ra->msg3_TPC = 1; } +/** @brief remove the UE with RNTI rnti from list of UEs doing RA. + * + * The corresponding function to add is add_new_UE_RA(). */ +void nr_release_ra_UE(gNB_MAC_INST *mac, rnti_t rnti) +{ + NR_UEs_t *UE_info = &mac->UE_info; + NR_SCHED_LOCK(&UE_info->mutex); + NR_UE_info_t *UE = remove_UE_from_list(NR_NB_RA_PROC_MAX, UE_info->access_ue_list, rnti); + NR_SCHED_UNLOCK(&UE_info->mutex); + if (UE) { + delete_nr_ue_data(UE, mac->common_channels, &UE_info->uid_allocator); + } else { + LOG_W(NR_MAC,"Call to del rnti %04x, but not existing\n", rnti); + } +} + void nr_schedule_RA(module_id_t module_idP, frame_t frameP, slot_t slotP, @@ -2268,38 +2254,33 @@ void nr_schedule_RA(module_id_t module_idP, start_meas(&mac->schedule_ra); for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; - for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { - NR_RA_t *ra = &cc->ra[i]; + UE_iterator(mac->UE_info.access_ue_list, UE) { + NR_RA_t *ra = UE->ra; if (ra->ra_state != nrRA_gNB_IDLE) - LOG_D(NR_MAC, "RA[%d] frame.slot %d.%d state: %d\n", i, frameP, slotP, ra->ra_state); + LOG_D(NR_MAC, "UE %04x frame.slot %d.%d RA state: %d\n", UE->rnti, frameP, slotP, ra->ra_state); - // Check RA Contention Resolution timer - if (ra->ra_type == RA_4_STEP && ra->ra_state >= nrRA_WAIT_Msg3) { + // Check RA Contention Resolution timer (TODO check this procedure) + if (ra->ra_type == RA_4_STEP && ra->ra_state > nrRA_WAIT_Msg3) { ra->contention_resolution_timer--; - if (ra->contention_resolution_timer < 0) { - LOG_W(NR_MAC, "(%d.%d) RA Contention Resolution timer expired for UE 0x%04x, RA procedure failed...\n", frameP, slotP, ra->rnti); - bool requested = nr_mac_request_release_ue(mac, ra->rnti); + if (ra->contention_resolution_timer == 0) { + LOG_W(NR_MAC, "(%d.%d) RA Contention Resolution timer expired for UE 0x%04x, RA procedure failed...\n", frameP, slotP, UE->rnti); + bool requested = nr_mac_request_release_ue(mac, UE->rnti); if (!requested) - nr_mac_release_ue(mac, ra->rnti); - nr_clear_ra_proc(ra); + nr_release_ra_UE(mac, UE->rnti); continue; } } switch (ra->ra_state) { case nrRA_Msg2: - nr_generate_Msg2(module_idP, CC_id, frameP, slotP, ra, DL_req, TX_req); + nr_generate_Msg2(module_idP, CC_id, frameP, slotP, UE, DL_req, TX_req); break; case nrRA_Msg3_retransmission: - nr_generate_Msg3_retransmission(module_idP, CC_id, frameP, slotP, ra, ul_dci_req); + nr_generate_Msg3_retransmission(module_idP, CC_id, frameP, slotP, UE, ul_dci_req); break; case nrRA_Msg4: case nrRA_MsgB: - nr_generate_Msg4_MsgB(module_idP, CC_id, frameP, slotP, ra, DL_req, TX_req); - break; - case nrRA_WAIT_Msg4_MsgB_ACK: - nr_check_Msg4_MsgB_Ack(module_idP, CC_id, frameP, slotP, ra); + nr_generate_Msg4_MsgB(module_idP, CC_id, frameP, slotP, UE, DL_req, TX_req); break; default: break; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index b69490fbc9..226fe80dbb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -323,7 +323,7 @@ int nr_write_ce_dlsch_pdu(module_id_t module_idP, static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, slot_t slot) { - UE_iterator(RC.nrmac[module_id]->UE_info.list, UE) { + UE_iterator(RC.nrmac[module_id]->UE_info.connected_ue_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; sched_ctrl->num_total_bytes = 0; sched_ctrl->dl_pdus_total = 0; @@ -609,9 +609,6 @@ static void pf_dl(module_id_t module_id, /* Loop UE_info->list to check retransmission */ UE_iterator(UE_list, UE) { - if (!UE->Msg4_MsgB_ACKed) - continue; - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; @@ -865,7 +862,7 @@ static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s gNB_MAC_INST *mac = RC.nrmac[module_id]; NR_UEs_t *UE_info = &mac->UE_info; - if (UE_info->list[0] == NULL) + if (UE_info->connected_ue_list[0] == NULL) return; NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; @@ -885,7 +882,7 @@ static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); /* proportional fair scheduling algorithm */ - pf_dl(module_id, frame, slot, UE_info->list, max_sched_ues, num_beams, n_rb_sched); + pf_dl(module_id, frame, slot, UE_info->connected_ue_list, max_sched_ues, num_beams, n_rb_sched); } nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id) { @@ -940,7 +937,7 @@ void nr_schedule_ue_spec(module_id_t module_id, const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; gNB_mac->mac_stats.total_prb_aggregate += NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE); - UE_iterator(UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 55d9738938..bc7b40937f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -62,7 +62,7 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot) int slot_period = slot % mac->frame_structure.numb_slots_period; if (!is_xlsch_in_slot(dlsch_slot_bitmap, slot_period)) return; - NR_UE_info_t *UE = mac->UE_info.list[0]; + NR_UE_info_t *UE = mac->UE_info.connected_ue_list[0]; NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; @@ -214,9 +214,9 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slo /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ NR_COMMON_channels_t *cc = nr_mac->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_UE_info_t *UE = nr_mac->UE_info.list[0]; + NR_UE_info_t *UE = nr_mac->UE_info.connected_ue_list[0]; - AssertFatal(nr_mac->UE_info.list[1] == NULL, + AssertFatal(nr_mac->UE_info.connected_ue_list[1] == NULL, "cannot handle more than one UE\n"); if (UE == NULL) return false; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index c294d2966a..7b9ad1ed3b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -125,16 +125,22 @@ static const uint16_t cqi_table3[16][2] = {{0, 0}, static void determine_aggregation_level_search_order(int agg_level_search_order[NUM_PDCCH_AGG_LEVELS], float pdcch_cl_adjust); -uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, - const nr_dci_format_t dci_format) { - +uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format) +{ // TODO check this but it should be enough for now // if there is not csi report activated RI is 0 from initialization if(dci_format == NR_DL_DCI_FORMAT_1_0) return 1; else - return (sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri + 1); + return sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri + 1; +} +int get_ul_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format) +{ + if(dci_format == NR_UL_DCI_FORMAT_0_0) + return 1; + else + return sched_ctrl->srs_feedback.ul_ri + 1; } // Table 5.2.2.2.1-3 and Table 5.2.2.2.1-4 in 38.214 @@ -292,7 +298,7 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc, int frontloaded_symb = 1; // default value nr_dci_format_t dci_format = dl_bwp ? dl_bwp->dci_format : NR_DL_DCI_FORMAT_1_0; if (dci_format == NR_DL_DCI_FORMAT_1_0) { - dmrs.numDmrsCdmGrpsNoData = tda_info->nrOfSymbols == 2 ? 1 : 2; + dmrs.numDmrsCdmGrpsNoData = tda_info->nrOfSymbols <= 2 ? 1 : 2; dmrs.dmrs_ports_id = 0; } else { @@ -394,10 +400,10 @@ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, } } -NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc, - NR_BWP_DownlinkDedicated_t *bwp_Dedicated, - NR_SearchSpace__searchSpaceType_PR target_ss) { - +static NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc, + NR_BWP_DownlinkDedicated_t *bwp_Dedicated, + NR_SearchSpace__searchSpaceType_PR target_ss) +{ int n = 0; if(bwp_Dedicated) n = bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count; @@ -696,7 +702,7 @@ NR_pusch_dmrs_t get_ul_dmrs_params(const NR_ServingCellConfigCommon_t *scc, dmrs.num_dmrs_cdm_grps_no_data = 2; } else { if (ul_bwp->transform_precoding && Layers < 3) - dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols == 2 ? 1 : 2; + dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols <= 2 ? 1 : 2; else dmrs.num_dmrs_cdm_grps_no_data = 2; } @@ -2060,8 +2066,18 @@ void remove_front_nr_list(NR_list_t *listP) NR_UE_info_t *find_nr_UE(NR_UEs_t *UEs, rnti_t rntiP) { + UE_iterator(UEs->connected_ue_list, UE) { + if (UE->rnti == rntiP) { + LOG_D(NR_MAC,"Search and found rnti: %04x\n", rntiP); + return UE; + } + } + return NULL; +} - UE_iterator(UEs->list, UE) { +NR_UE_info_t *find_ra_UE(NR_UEs_t *UEs, rnti_t rntiP) +{ + UE_iterator(UEs->access_ue_list, UE) { if (UE->rnti == rntiP) { LOG_D(NR_MAC,"Search and found rnti: %04x\n", rntiP); return UE; @@ -2073,7 +2089,6 @@ NR_UE_info_t *find_nr_UE(NR_UEs_t *UEs, rnti_t rntiP) void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_allocator_t *uia) { ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); - ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->reconfigCellGroup); ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->capability); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; seq_arr_free(&sched_ctrl->lc_config, NULL); @@ -2088,6 +2103,7 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_alloca free_sched_pucch_list(sched_ctrl); uid_linear_allocator_free(uia, UE->uid); LOG_I(NR_MAC, "Remove NR rnti 0x%04x\n", UE->rnti); + free_and_zero(UE->ra); free(UE); } @@ -2195,31 +2211,17 @@ static void set_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl, // main function to configure parameters of current BWP void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_ServingCellConfigCommon_t *scc, - NR_UE_sched_ctrl_t *sched_ctrl, - NR_RA_t *ra, NR_UE_info_t *UE, + bool is_RA, + int target_ss, int dl_bwp_switch, int ul_bwp_switch) { - AssertFatal((ra != NULL && UE == NULL) || (ra == NULL && UE != NULL), "RA and UE structures are mutually exlusive in BWP configuration\n"); + NR_CellGroupConfig_t *CellGroup = UE->CellGroup; + NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info; + NR_UE_DL_BWP_t *DL_BWP = &UE->current_DL_BWP; + NR_UE_UL_BWP_t *UL_BWP = &UE->current_UL_BWP; - NR_CellGroupConfig_t *CellGroup; - NR_UE_ServingCell_Info_t *sc_info; - NR_UE_DL_BWP_t *DL_BWP; - NR_UE_UL_BWP_t *UL_BWP; - - if (ra) { - DL_BWP = &ra->DL_BWP; - UL_BWP = &ra->UL_BWP; - CellGroup = ra->CellGroup; - sc_info = &ra->sc_info; - } - else { - DL_BWP = &UE->current_DL_BWP; - UL_BWP = &UE->current_UL_BWP; - CellGroup = UE->CellGroup; - sc_info = &UE->sc_info; - } NR_BWP_Downlink_t *dl_bwp = NULL; NR_BWP_Uplink_t *ul_bwp = NULL; NR_BWP_DownlinkDedicated_t *bwpd = NULL; @@ -2230,15 +2232,10 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, int old_dl_bwp_id = DL_BWP->bwp_id; int old_ul_bwp_id = UL_BWP->bwp_id; - int target_ss; - NR_ServingCellConfig_t *servingCellConfig = NULL; - if (CellGroup && - CellGroup->spCellConfig && - CellGroup->spCellConfig->spCellConfigDedicated) { + if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated) { servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated; - target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; if(dl_bwp_switch >= 0 && ul_bwp_switch >= 0) { AssertFatal(dl_bwp_switch == ul_bwp_switch, "Different UL and DL BWP not supported\n"); @@ -2298,7 +2295,6 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, else { DL_BWP->bwp_id = 0; UL_BWP->bwp_id = 0; - target_ss = NR_SearchSpace__searchSpaceType_PR_common; DL_BWP->pdsch_Config = NULL; UL_BWP->pusch_Config = NULL; UL_BWP->pucch_Config = NULL; @@ -2359,7 +2355,10 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, UL_BWP->rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; } - if(UE) { + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + // Reset required fields in sched_ctrl (e.g. ul_ri and tpmi) + reset_sched_ctrl(sched_ctrl); + if(!is_RA) { if (servingCellConfig) { if (servingCellConfig->csi_MeasConfig) { sc_info->csi_MeasConfig = servingCellConfig->csi_MeasConfig->choice.setup; @@ -2398,23 +2397,16 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, sc_info->nrofHARQ_ProcessesForPUSCH_r17 = pusch_servingcellconfig->ext3->nrofHARQ_ProcessesForPUSCH_r17; } } + create_dl_harq_list(sched_ctrl, sc_info); + create_ul_harq_list(sched_ctrl, sc_info); } if (CellGroup && CellGroup->physicalCellGroupConfig) UE->pdsch_HARQ_ACK_Codebook = CellGroup->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook; - // Reset required fields in sched_ctrl (e.g. ul_ri and tpmi) - reset_sched_ctrl(sched_ctrl); - // setting PDCCH related structures for sched_ctrl - sched_ctrl->search_space = get_searchspace(scc, - bwpd, - target_ss); - sched_ctrl->coreset = get_coreset(nr_mac, - scc, - bwpd, - sched_ctrl->search_space, - target_ss); + sched_ctrl->search_space = get_searchspace(scc, bwpd, target_ss); + sched_ctrl->coreset = get_coreset(nr_mac, scc, bwpd, sched_ctrl->search_space, target_ss); sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac, sched_ctrl->search_space, @@ -2436,11 +2428,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) : NR_UL_DCI_FORMAT_0_0; - set_max_fb_time(UL_BWP, DL_BWP); - set_sched_pucch_list(sched_ctrl, UL_BWP, scc, &nr_mac->frame_structure); - } - - if(ra) { + } else { // setting PDCCH related structures for RA struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL; NR_SearchSpaceId_t ra_SearchSpace = 0; @@ -2453,26 +2441,29 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, } AssertFatal(commonSearchSpaceList->list.count > 0, "common SearchSpace list has 0 elements\n"); for (int i = 0; i < commonSearchSpaceList->list.count; i++) { - NR_SearchSpace_t * ss = commonSearchSpaceList->list.array[i]; + NR_SearchSpace_t *ss = commonSearchSpaceList->list.array[i]; if (ss->searchSpaceId == ra_SearchSpace) - ra->ra_ss = ss; + sched_ctrl->search_space = ss; } - AssertFatal(ra->ra_ss!=NULL,"SearchSpace cannot be null for RA\n"); + AssertFatal(sched_ctrl->search_space != NULL, "SearchSpace cannot be null for RA\n"); - ra->coreset = get_coreset(nr_mac, scc, dl_bwp, ra->ra_ss, NR_SearchSpace__searchSpaceType_PR_common); + sched_ctrl->coreset = get_coreset(nr_mac, scc, dl_bwp, sched_ctrl->search_space, NR_SearchSpace__searchSpaceType_PR_common); NR_COMMON_channels_t *cc = &nr_mac->common_channels[0]; - int ssb_index = cc->ssb_index[ra->beam_id]; - ra->sched_pdcch = set_pdcch_structure(nr_mac, - ra->ra_ss, - ra->coreset, - scc, - &dl_genericParameters, - &nr_mac->type0_PDCCH_CSS_config[ssb_index]); + int ssb_index = cc->ssb_index[UE->UE_beam_index]; + sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac, + sched_ctrl->search_space, + sched_ctrl->coreset, + scc, + &dl_genericParameters, + &nr_mac->type0_PDCCH_CSS_config[ssb_index]); UL_BWP->dci_format = NR_UL_DCI_FORMAT_0_0; DL_BWP->dci_format = NR_DL_DCI_FORMAT_1_0; } + set_max_fb_time(UL_BWP, DL_BWP); + set_sched_pucch_list(sched_ctrl, UL_BWP, scc, &nr_mac->frame_structure); + // Set MCS tables long *dl_mcs_Table = DL_BWP->pdsch_Config ? DL_BWP->pdsch_Config->mcs_Table : NULL; DL_BWP->mcsTableIdx = get_pdsch_mcs_table(dl_mcs_Table, DL_BWP->dci_format, TYPE_C_RNTI_, target_ss); @@ -2482,9 +2473,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, // Set uplink MCS table long *mcs_Table = NULL; if (UL_BWP->pusch_Config) - mcs_Table = UL_BWP->transform_precoding ? - UL_BWP->pusch_Config->mcs_Table : - UL_BWP->pusch_Config->mcs_TableTransformPrecoder; + mcs_Table = UL_BWP->transform_precoding ? UL_BWP->pusch_Config->mcs_Table : UL_BWP->pusch_Config->mcs_TableTransformPrecoder; UL_BWP->mcs_table = get_pusch_mcs_table(mcs_Table, !UL_BWP->transform_precoding, UL_BWP->dci_format, TYPE_C_RNTI_, target_ss, false); } @@ -2502,49 +2491,29 @@ static void init_bler_stats(const NR_bler_options_t *bler_options, NR_bler_stats bler_stats->bler = (float)(bler_options->lower + bler_options->upper) / 2.0f; } -//------------------------------------------------------------------------------ -NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup) +/* @brief returns a new UE allocated instance. + * + * It will be typically added to the access_ue_list, but not always (e.g., + * phytest mode), so this is not done in this function (and also, to allow + * error handling). Remove with delete_nr_ue_data(). */ +NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup) { - NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon; - NR_UEs_t *UE_info = &nr_mac->UE_info; - LOG_I(NR_MAC, "Adding new UE context with RNTI 0x%04x\n", rntiP); - dump_nr_list(UE_info->list); - - // We will attach at the end, to mitigate race conditions - // This is not good, but we will fix it progressively - NR_UE_info_t *UE = calloc(1, sizeof(NR_UE_info_t)); - if(!UE) { - LOG_E(NR_MAC,"want to add UE %04x but the fixed allocated size is full\n",rntiP); + uid_t uid = uid_linear_allocator_new(uia); + /* if the UE list is full, we should reject the UE with an RRC reject + * message, but we do not have this functionality. To keep it simple, do not + * create a UE context here, so we can print an error message. */ + if (uid >= MAX_MOBILES_PER_GNB) { + uid_linear_allocator_free(uia, uid); return NULL; } - UE->rnti = rntiP; - UE->uid = uid_linear_allocator_new(&UE_info->uid_allocator); + NR_UE_info_t *UE = calloc_or_fail(1, sizeof(NR_UE_info_t)); + UE->rnti = rnti; UE->CellGroup = CellGroup; - - UE->Msg4_MsgB_ACKed = CellGroup != NULL; - + UE->uid = uid; + UE->ra = calloc(1, sizeof(*UE->ra)); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - memset(sched_ctrl, 0, sizeof(*sched_ctrl)); - sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */ sched_ctrl->ta_update = 31; - sched_ctrl->sched_srs.frame = -1; - sched_ctrl->sched_srs.slot = -1; - sched_ctrl->pdcch_cl_adjust = 0; - - // Initialize bler_stats - init_bler_stats(&nr_mac->dl_bler, &sched_ctrl->dl_bler_stats, nr_mac->frame); - init_bler_stats(&nr_mac->ul_bler, &sched_ctrl->ul_bler_stats, nr_mac->frame); - - // initialize LCID structure - seq_arr_init(&sched_ctrl->lc_config, sizeof(nr_lc_config_t)); - - // initialize UE BWP information - NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; - memset(dl_bwp, 0, sizeof(*dl_bwp)); - NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; - memset(ul_bwp, 0, sizeof(*ul_bwp)); - configure_UE_BWP(nr_mac, scc, sched_ctrl, NULL, UE, -1, -1); /* set illegal time domain allocation to force recomputation of all fields */ sched_ctrl->sched_pdsch.time_domain_allocation = -1; @@ -2558,27 +2527,87 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf create_dl_harq_list(sched_ctrl, &UE->sc_info); create_ul_harq_list(sched_ctrl, &UE->sc_info); - reset_srs_stats(UE); + // initialize LCID structure + seq_arr_init(&sched_ctrl->lc_config, sizeof(nr_lc_config_t)); + return UE; +} - NR_SCHED_LOCK(&UE_info->mutex); - int i; - for(i=0; ilist[i] == NULL) { - UE_info->list[i] = UE; - break; +bool add_UE_to_list(int list_size, NR_UE_info_t *list[list_size], NR_UE_info_t *UE) +{ + for (int i = 0; i < list_size; i++) { + if (!list[i]) { + list[i] = UE; + return true; } } - if (i == MAX_MOBILES_PER_GNB) { - LOG_E(NR_MAC,"Try to add UE %04x but the list is full\n", rntiP); - delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); - NR_SCHED_UNLOCK(&UE_info->mutex); - return NULL; - } - NR_SCHED_UNLOCK(&UE_info->mutex); + return false; +} - LOG_D(NR_MAC, "Add NR rnti %x\n", rntiP); - dump_nr_list(UE_info->list); - return (UE); +NR_UE_info_t *remove_UE_from_list(int list_size, NR_UE_info_t *list[list_size], rnti_t rnti) +{ + for (int i = 0; i < list_size; i++) { + NR_UE_info_t *curr_UE = list[i]; + if (curr_UE->rnti != rnti) + continue; + + /* remove this UE from the list, return the pointer */ + memmove(&list[i], &list[i+1], sizeof(list[0]) * (list_size - i - 1)); + list[list_size - 1] = NULL; + return curr_UE; + } + LOG_E(NR_MAC, "UE %04x to be removed not found in list\n", rnti); + return NULL; +} + +/** @brief Transitions a UE from access list to connected list (i.e., the RA + * list to the "normal" UE context list. */ +bool transition_ra_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) +{ + NR_UEs_t *UE_info = &nr_mac->UE_info; + + // remove UE from initial access list (moved to connected mode) + NR_UE_info_t *r = remove_UE_from_list(NR_NB_RA_PROC_MAX, UE_info->access_ue_list, UE->rnti); + DevAssert(r == UE); /* sanity check: we should have removed the current UE ptr from list */ + + free_and_zero(UE->ra); + + return add_connected_nr_ue(nr_mac, UE); +} + +/** @brief Add a UE to the list of UEs in * connected mode. + * + * To remove the UE, use mac_remove_nr_ue(). */ +bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) +{ + LOG_I(NR_MAC, "Adding new UE context with RNTI 0x%04x\n", UE->rnti); + NR_UEs_t *UE_info = &nr_mac->UE_info; + dump_nr_list(UE_info->connected_ue_list); + AssertFatal(!UE->ra, "UE in connected cannot have RA process\n"); + + NR_SCHED_LOCK(&UE_info->mutex); + + bool success = add_UE_to_list(MAX_MOBILES_PER_GNB, UE_info->connected_ue_list, UE); + if (!success) { + LOG_E(NR_MAC,"Try to add UE %04x but the list is full\n", UE->rnti); + delete_nr_ue_data(UE, NULL, &UE_info->uid_allocator); + NR_SCHED_UNLOCK(&UE_info->mutex); + return false; + } + + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */ + sched_ctrl->sched_srs.frame = -1; + sched_ctrl->sched_srs.slot = -1; + sched_ctrl->pdcch_cl_adjust = 0; + reset_srs_stats(UE); + + // Initialize bler_stats + init_bler_stats(&nr_mac->dl_bler, &sched_ctrl->dl_bler_stats, nr_mac->frame); + init_bler_stats(&nr_mac->ul_bler, &sched_ctrl->ul_bler_stats, nr_mac->frame); + + NR_SCHED_UNLOCK(&UE_info->mutex); + dump_nr_list(UE_info->connected_ue_list); + return true; } void free_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl) @@ -2683,38 +2712,11 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti) { /* already mutex protected */ NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock); - NR_UEs_t *UE_info = &nr_mac->UE_info; NR_SCHED_LOCK(&UE_info->mutex); - UE_iterator(UE_info->list, UE) { - if (UE->rnti==rnti) - break; - } - - if (!UE) { - LOG_W(NR_MAC,"Call to del rnti %04x, but not existing\n", rnti); - NR_SCHED_UNLOCK(&UE_info->mutex); - return; - } - - NR_UE_info_t * newUEs[MAX_MOBILES_PER_GNB+1]={0}; - int newListIdx=0; - for (int i=0; ilist[i] && UE_info->list[i]->rnti != rnti) - newUEs[newListIdx++]=UE_info->list[i]; - memcpy(UE_info->list, newUEs, sizeof(UE_info->list)); + NR_UE_info_t *UE = remove_UE_from_list(MAX_MOBILES_PER_GNB + 1, UE_info->connected_ue_list, rnti); NR_SCHED_UNLOCK(&UE_info->mutex); - const int CC_id = 0; - NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; - for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { - NR_RA_t *ra = &cc->ra[i]; - if (ra->rnti == UE->rnti) { - nr_clear_ra_proc(ra); - ra->cfra = 0; - } - } - delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); } @@ -2799,7 +2801,7 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt UE_info->sched_csirs = 0; - UE_iterator(UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; // CSI-RS is common to all UEs in a given BWP @@ -3030,7 +3032,7 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt } } -static void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) +void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) { DevAssert(cell_group != NULL); /* remove a reconfigurationWithSync, we don't need it anymore */ @@ -3050,38 +3052,6 @@ static void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) 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, slot_t slot) -{ - LOG_D(NR_MAC, "%4d.%2d RNTI %04x: UE inactivity timer expired\n", frame, slot, UE->rnti); - - /* check if there is a new CellGroupConfig to be applied */ - if (UE->interrupt_action == FOLLOW_INSYNC_RECONFIG && UE->reconfigCellGroup != NULL) { - LOG_D(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after UE inactivity\n", frame, slot, UE->rnti); - ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); - UE->CellGroup = UE->reconfigCellGroup; - UE->reconfigCellGroup = NULL; - UE->interrupt_action = FOLLOW_INSYNC; - - if (LOG_DEBUGFLAG(DEBUG_ASN1)) - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)UE->CellGroup); - - nr_mac_clean_cellgroup(UE->CellGroup); - } - - NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; - - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - configure_UE_BWP(mac, scc, sched_ctrl, NULL, UE, -1, -1); - - reset_srs_stats(UE); - - if (IS_SA_MODE(get_softmodem_params())) { - // add all available DL,UL HARQ processes for this UE in SA - create_dl_harq_list(sched_ctrl, &UE->sc_info); - create_ul_harq_list(sched_ctrl, &UE->sc_info); - } -} - int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs) { /* we previously assumed a specific "slot ahead" value for the PHY processing @@ -3109,7 +3079,7 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interr // frames, after the inactivity of the UE. UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024; - LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots) action %d reconfigCellGroup %p\n", UE->rnti, slots, UE->interrupt_action, UE->reconfigCellGroup); + LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots) action %d\n", UE->rnti, slots, UE->interrupt_action); return 0; } @@ -3161,7 +3131,7 @@ void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot) NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); NR_UEs_t *UE_info = &mac->UE_info; - UE_iterator(UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; if (nr_mac_check_release(sched_ctrl, UE->rnti)) { @@ -3182,8 +3152,6 @@ void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot) nr_timer_stop(&sched_ctrl->transm_interrupt); if (UE->interrupt_action == FOLLOW_OUTOFSYNC) nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs); - else - nr_mac_apply_cellgroup(mac, UE, frame, slot); } } } @@ -3519,24 +3487,14 @@ bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid) return true; } -static const NR_RA_t *find_nr_RA_rnti(const NR_RA_t *ra_base, int ra_count, rnti_t rnti) -{ - for (int i = 0; i < ra_count; ++i) { - const NR_RA_t *ra = &ra_base[i]; - if (ra->ra_state != nrRA_gNB_IDLE && ra->rnti == rnti) - return ra; - } - return NULL; -} - -bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti) +bool nr_mac_get_new_rnti(NR_UEs_t *UEs, rnti_t *rnti) { int loop = 0; bool exist_connected_ue, exist_in_pending_ra_ue; do { *rnti = (taus() % 0xffef) + 1; exist_connected_ue = find_nr_UE(UEs, *rnti) != NULL; - exist_in_pending_ra_ue = find_nr_RA_rnti(ra_base, ra_count, *rnti) != NULL; + exist_in_pending_ra_ue = find_ra_UE(UEs, *rnti) != NULL; loop++; } while (loop < 100 && (exist_connected_ue || exist_in_pending_ra_ue)); return loop < 100; // nothing found: loop count 100 diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 2f6313de96..c3ebb5ab9b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -521,7 +521,7 @@ void nr_schedule_srs(int module_id, frame_t frame, int slot) NR_UEs_t *UE_info = &nrmac->UE_info; - UE_iterator(UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { const int CC_id = 0; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index ddb5ba9ead..29ff27d38e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -171,39 +171,54 @@ static int get_pucch_index(int frame, int slot, const frame_structure_t *fs, int return (frame_start + ul_period_start + ul_period_slot) % sched_pucch_size; } -void nr_schedule_pucch(gNB_MAC_INST *nrmac, frame_t frameP, slot_t slotP) +static void schedule_pucch_core(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, frame_t frame, slot_t slot) +{ + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + const int pucch_index = get_pucch_index(frame, slot, &nrmac->frame_structure, sched_ctrl->sched_pucch_size); + NR_sched_pucch_t *curr_pucch = &UE->UE_sched_ctrl.sched_pucch[pucch_index]; + if (!curr_pucch->active) + return; + if (frame != curr_pucch->frame || slot != curr_pucch->ul_slot) { + LOG_E(NR_MAC, + "PUCCH frame/slot mismatch: current %4d.%2d vs. request %4d.%2d: not scheduling PUCCH\n", + curr_pucch->frame, + curr_pucch->ul_slot, + frame, + slot); + memset(curr_pucch, 0, sizeof(*curr_pucch));; + return; + } + + const uint16_t O_ack = curr_pucch->dai_c; + const uint16_t O_csi = curr_pucch->csi_bits; + const uint8_t O_sr = curr_pucch->sr_flag; + LOG_D(NR_MAC, + "Scheduling PUCCH[%d] RX for UE %04x in %4d.%2d O_ack %d, O_sr %d, O_csi %d\n", + pucch_index, + UE->rnti, + curr_pucch->frame, + curr_pucch->ul_slot, + O_ack,O_sr, + O_csi); + nr_fill_nfapi_pucch(nrmac, frame, slot, curr_pucch, UE); + memset(curr_pucch, 0, sizeof(*curr_pucch)); +} + +void nr_schedule_pucch(gNB_MAC_INST *nrmac, frame_t frame, slot_t slot) { /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock); - if (!is_ul_slot(slotP, &nrmac->frame_structure)) + if (!is_ul_slot(slot, &nrmac->frame_structure)) return; - UE_iterator(nrmac->UE_info.list, UE) { - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - const int pucch_index = get_pucch_index(frameP, slotP, &nrmac->frame_structure, sched_ctrl->sched_pucch_size); - NR_sched_pucch_t *curr_pucch = &UE->UE_sched_ctrl.sched_pucch[pucch_index]; - if (!curr_pucch->active) - continue; - if (frameP != curr_pucch->frame || slotP != curr_pucch->ul_slot) { - LOG_E(NR_MAC, - "PUCCH frame/slot mismatch: current %4d.%2d vs. request %4d.%2d: not scheduling PUCCH\n", - curr_pucch->frame, - curr_pucch->ul_slot, - frameP, - slotP); - memset(curr_pucch, 0, sizeof(*curr_pucch));; - continue; - } - - const uint16_t O_ack = curr_pucch->dai_c; - const uint16_t O_csi = curr_pucch->csi_bits; - const uint8_t O_sr = curr_pucch->sr_flag; - LOG_D(NR_MAC,"Scheduling PUCCH[%d] RX for UE %04x in %4d.%2d O_ack %d, O_sr %d, O_csi %d\n", - pucch_index,UE->rnti,curr_pucch->frame,curr_pucch->ul_slot,O_ack,O_sr,O_csi); - nr_fill_nfapi_pucch(nrmac, frameP, slotP, curr_pucch, UE); - memset(curr_pucch, 0, sizeof(*curr_pucch)); + UE_iterator(nrmac->UE_info.access_ue_list, init_UE) { + if (init_UE->ra->ra_state == nrRA_WAIT_Msg4_MsgB_ACK) + schedule_pucch_core(nrmac, init_UE, frame, slot); + } + UE_iterator(nrmac->UE_info.connected_ue_list, UE) { + schedule_pucch_core(nrmac, UE, frame, slot); } } @@ -217,7 +232,7 @@ void nr_csi_meas_reporting(int Mod_idP,frame_t frame, slot_t slot) /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock); - UE_iterator(nrmac->UE_info.list, UE ) { + UE_iterator(nrmac->UE_info.connected_ue_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; const int n_slots_frame = nrmac->frame_structure.numb_slots_frame; @@ -854,14 +869,19 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con gNB_MAC_INST *nrmac = RC.nrmac[mod_id]; int rssi_threshold = nrmac->pucch_rssi_threshold; NR_SCHED_LOCK(&nrmac->sched_lock); - NR_UE_info_t * UE = find_nr_UE(&nrmac->UE_info, uci_01->rnti); + NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, uci_01->rnti); + bool is_ra = false; if (!UE) { - LOG_E(NR_MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_01->rnti); - NR_SCHED_UNLOCK(&nrmac->sched_lock); - return; + UE = find_ra_UE(&nrmac->UE_info, uci_01->rnti); + if (UE) + is_ra = true; + else { + LOG_E(NR_MAC, "Unknown RNTI %04x in PUCCH UCI\n", uci_01->rnti); + NR_SCHED_UNLOCK(&nrmac->sched_lock); + return; + } } NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - if (((uci_01->pduBitmap >> 1) & 0x01)) { // iterate over received harq bits for (int harq_bit = 0; harq_bit < uci_01->harq.num_harq; harq_bit++) { @@ -877,10 +897,12 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con remove_front_nr_list(&sched_ctrl->feedback_dl_harq); LOG_D(NR_MAC,"%4d.%2d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit,pid,harq_value); nr_mac_update_pdcch_closed_loop_adjust(sched_ctrl, harq_confidence != 0); - handle_dl_harq(UE, pid, harq_value == 0 && harq_confidence == 0, nrmac->dl_bler.harq_round_max); - if (!UE->Msg4_MsgB_ACKed && harq_value == 0 && harq_confidence == 0) - UE->Msg4_MsgB_ACKed = true; - if (harq_confidence == 1) UE->mac_stats.pucch0_DTX++; + bool success = harq_value == 0 && harq_confidence == 0; + handle_dl_harq(UE, pid, success, nrmac->dl_bler.harq_round_max); + if (is_ra) + nr_check_Msg4_MsgB_Ack(mod_id, frame, slot, UE, success); + if (harq_confidence == 1) + UE->mac_stats.pucch0_DTX++; } // tpc (power control) only if we received AckNack @@ -1219,7 +1241,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, slot_t slot) if (!is_ul_slot(slot, &nrmac->frame_structure)) return; const int CC_id = 0; - UE_iterator(nrmac->UE_info.list, UE) { + UE_iterator(nrmac->UE_info.connected_ue_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; const int n_slots_frame = nrmac->frame_structure.numb_slots_frame; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index c4cfd4181e..258f3c8c76 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -56,7 +56,7 @@ int get_ul_tda(gNB_MAC_INST *nrmac, int frame, int slot) } // Avoid slots with the SRS - UE_iterator(nrmac->UE_info.list, UE) { + UE_iterator(nrmac->UE_info.connected_ue_list, UE) { NR_sched_srs_t sched_srs = UE->UE_sched_ctrl.sched_srs; if(sched_srs.srs_scheduled && sched_srs.frame == frame && sched_srs.slot == slot) return 1; @@ -461,17 +461,13 @@ static int nr_process_mac_pdu(instance_t module_idP, break; case UL_SCH_LCID_C_RNTI: - for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { - NR_RA_t *ra = &RC.nrmac[module_idP]->common_channels[CC_id].ra[i]; - if (ra->ra_state == nrRA_gNB_IDLE && ra->rnti == UE->rnti) { - // Extract C-RNTI value - rnti_t crnti = ((pduP[1] & 0xFF) << 8) | (pduP[2] & 0xFF); - AssertFatal(false, - "Received MAC CE for C-RNTI %04x without RA running, procedure exists? Or is it a bug while decoding the " - "MAC PDU?\n", - crnti); - break; - } + if (UE->ra && UE->ra->ra_state == nrRA_gNB_IDLE) { + // Extract C-RNTI value + rnti_t crnti = ((pduP[1] & 0xFF) << 8) | (pduP[2] & 0xFF); + AssertFatal(false, + "Received MAC CE for C-RNTI %04x without RA running, procedure exists? Or is it a bug while decoding the " + "MAC PDU?\n", + crnti); } break; @@ -547,65 +543,31 @@ static void abort_nr_ul_harq(NR_UE_info_t *UE, int8_t harq_pid) sched_ctrl->sched_ul_bytes = 0; } -static bool get_UE_waiting_CFRA_msg3(const gNB_MAC_INST *gNB_mac, - const int CC_id, - const frame_t frame, - const slot_t slot, - rnti_t rnti) +static void handle_nr_ul_harq(gNB_MAC_INST *nrmac, + NR_UE_info_t *UE, + frame_t frame, + slot_t slot, + rnti_t rnti, + int crc_harq_id, + bool crc_status) { - bool UE_waiting_CFRA_msg3 = false; - for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { - const NR_RA_t *ra = &gNB_mac->common_channels[CC_id].ra[i]; - if (ra->cfra && ra->ra_state == nrRA_WAIT_Msg3 && frame == ra->Msg3_frame && slot == ra->Msg3_slot && rnti == ra->rnti) { - UE_waiting_CFRA_msg3 = true; - break; - } - } - return UE_waiting_CFRA_msg3; -} - -void handle_nr_ul_harq(const int CC_idP, module_id_t mod_id, frame_t frame, slot_t slot, const nfapi_nr_crc_t *crc_pdu) -{ - gNB_MAC_INST *nrmac = RC.nrmac[mod_id]; if (nrmac->radio_config.disable_harq) { LOG_D(NR_MAC, "skipping UL feedback handling as HARQ is disabled\n"); return; } - NR_SCHED_LOCK(&nrmac->sched_lock); - for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) { - NR_RA_t *ra = &nrmac->common_channels[CC_idP].ra[i]; - // if we find any ongoing RA that has already scheduled MSG3 - // and it is expecting its reception in current frame and slot with matching RNTI - // we can exit the function (no HARQ involved) - if (ra->ra_state >= nrRA_WAIT_Msg3 && ra->rnti == crc_pdu->rnti && frame == ra->Msg3_frame && slot == ra->Msg3_slot) { - LOG_D(NR_MAC, "UL for rnti %04x in RA (MSG3), no need to process HARQ\n", crc_pdu->rnti); - NR_SCHED_UNLOCK(&nrmac->sched_lock); - return; - } - } - - NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, crc_pdu->rnti); - if (!UE) { - NR_SCHED_UNLOCK(&nrmac->sched_lock); - LOG_E(NR_MAC, "Couldn't identify UE connected with current UL HARQ process\n"); - return; - } - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; int8_t harq_pid = sched_ctrl->feedback_ul_harq.head; - LOG_D(NR_MAC, "Comparing crc_pdu->harq_id vs feedback harq_pid = %d %d\n",crc_pdu->harq_id, harq_pid); - while (crc_pdu->harq_id != harq_pid || harq_pid < 0) { - LOG_W(NR_MAC, "Unexpected ULSCH HARQ PID %d (have %d) for RNTI 0x%04x\n", crc_pdu->harq_id, harq_pid, crc_pdu->rnti); - if (harq_pid < 0) { - NR_SCHED_UNLOCK(&nrmac->sched_lock); + LOG_D(NR_MAC, "Comparing crc harq_id vs feedback harq_pid = %d %d\n", crc_harq_id, harq_pid); + while (crc_harq_id != harq_pid || harq_pid < 0) { + LOG_W(NR_MAC, "Unexpected ULSCH HARQ PID %d (have %d) for RNTI 0x%04x\n", crc_harq_id, harq_pid, rnti); + if (harq_pid < 0) return; - } remove_front_nr_list(&sched_ctrl->feedback_ul_harq); sched_ctrl->ul_harq_processes[harq_pid].is_waiting = false; - if(sched_ctrl->ul_harq_processes[harq_pid].round >= RC.nrmac[mod_id]->ul_bler.harq_round_max - 1) { + if(sched_ctrl->ul_harq_processes[harq_pid].round >= nrmac->ul_bler.harq_round_max - 1) { abort_nr_ul_harq(UE, harq_pid); } else { sched_ctrl->ul_harq_processes[harq_pid].round++; @@ -618,52 +580,211 @@ void handle_nr_ul_harq(const int CC_idP, module_id_t mod_id, frame_t frame, slot DevAssert(harq->is_waiting); harq->feedback_slot = -1; harq->is_waiting = false; - if (!crc_pdu->tb_crc_status) { + if (!crc_status) { finish_nr_ul_harq(sched_ctrl, harq_pid); LOG_D(NR_MAC, "Ulharq id %d crc passed for RNTI %04x\n", harq_pid, - crc_pdu->rnti); - } else if (harq->round >= RC.nrmac[mod_id]->ul_bler.harq_round_max - 1) { + rnti); + } else if (harq->round >= nrmac->ul_bler.harq_round_max - 1) { abort_nr_ul_harq(UE, harq_pid); LOG_D(NR_MAC, "RNTI %04x: Ulharq id %d crc failed in all rounds\n", - crc_pdu->rnti, + rnti, harq_pid); } else { harq->round++; LOG_D(NR_MAC, "Ulharq id %d crc failed for RNTI %04x\n", harq_pid, - crc_pdu->rnti); + rnti); add_tail_nr_list(&sched_ctrl->retrans_ul_harq, harq_pid); } - NR_SCHED_UNLOCK(&nrmac->sched_lock); } -static void handle_msg3_failed_rx(NR_RA_t *ra, int i, int harq_round_max) +static void handle_msg3_failed_rx(gNB_MAC_INST *mac, NR_RA_t *ra, rnti_t rnti, int harq_round_max) { // for CFRA (NSA) do not schedule retransmission of msg3 if (ra->cfra) { - LOG_D(NR_MAC, "Random Access %i failed at state %s (NSA msg3 reception failed)\n", i, nrra_text[ra->ra_state]); - nr_clear_ra_proc(ra); + LOG_W(NR_MAC, "UE %04x RA failed at state %s (NSA msg3 reception failed)\n", rnti, nrra_text[ra->ra_state]); + nr_release_ra_UE(mac, rnti); return; } if (ra->msg3_round >= harq_round_max - 1) { - LOG_W(NR_MAC, "Random Access %i failed at state %s (Reached msg3 max harq rounds)\n", i, nrra_text[ra->ra_state]); - nr_clear_ra_proc(ra); + LOG_W(NR_MAC, "UE %04x RA failed at state %s (Reached msg3 max harq rounds)\n", rnti, nrra_text[ra->ra_state]); + nr_release_ra_UE(mac, rnti); return; } - LOG_D(NR_MAC, "Random Access %i Msg3 CRC did not pass\n", i); + LOG_D(NR_MAC, "UE %04x Msg3 CRC did not pass\n", rnti); ra->msg3_round++; ra->ra_state = nrRA_Msg3_retransmission; } -/* -* When data are received on PHY and transmitted to MAC -*/ +static void nr_rx_ra_sdu(const module_id_t mod_id, + const int CC_id, + const frame_t frame, + const sub_frame_t slot, + rnti_t rnti, + uint8_t *sdu, + const uint32_t sdu_len, + const uint16_t timing_advance, + const uint8_t ul_cqi, + const uint16_t rssi) +{ + gNB_MAC_INST *mac = RC.nrmac[mod_id]; + NR_UE_info_t *UE = find_ra_UE(&mac->UE_info, rnti); + if (!UE) { + LOG_E(NR_MAC, "UL SDU discarded. Couldn't finde UE with RNTI %04x \n", rnti); + return; + } + + NR_RA_t *ra = UE->ra; + if (ra->ra_type == RA_4_STEP && ra->ra_state != nrRA_WAIT_Msg3) { + LOG_W(NR_MAC, "UL SDU discarded for RNTI %04x RA state not waiting for PUSCH\n", UE->rnti); + return; + } + + const int target_snrx10 = mac->pusch_target_snrx10; + if (!sdu) { // NACK + if (ra->ra_state != nrRA_WAIT_Msg3) + return; + + if((frame!=ra->Msg3_frame) || (slot!=ra->Msg3_slot)) + return; + + if (ul_cqi != 0xff) + ra->msg3_TPC = nr_get_tpc(target_snrx10, ul_cqi, 30, 0); + + handle_msg3_failed_rx(mac, ra, rnti, mac->ul_bler.harq_round_max); + return; + } + + + bool no_sig = true; + for (uint32_t k = 0; k < sdu_len; k++) { + if (sdu[k] != 0) { + no_sig = false; + break; + } + } + + T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(mod_id), T_INT(CC_id), + T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(-1) /* harq_pid */, + T_BUFFER(sdu, sdu_len)); + + + if (no_sig) { + LOG_W(NR_MAC, "MSG3 ULSCH with no signal\n"); + handle_msg3_failed_rx(mac, ra, rnti, mac->ul_bler.harq_round_max); + return; + } + if (ra->ra_type == RA_2_STEP) { + // random access pusch with RA-RNTI + if (ra->RA_rnti != rnti) { + LOG_E(NR_MAC, "expected TC_RNTI %04x to match current RNTI %04x\n", ra->RA_rnti, rnti); + return; + } + } + + // re-initialize ta update variables after RA procedure completion + UE->UE_sched_ctrl.ta_frame = frame; + + LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frame, slot, rnti); + + NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl; + if (ul_cqi != 0xff) { + UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30, UE_scheduling_control->sched_pusch.phr_txpower_calc); + UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - UE_scheduling_control->sched_pusch.phr_txpower_calc * 10; + } + if (timing_advance != 0xffff) + UE_scheduling_control->ta_update = timing_advance; + UE_scheduling_control->raw_rssi = rssi; + LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n", UE->rnti, UE_scheduling_control->tpc0, UE_scheduling_control->ta_update); + NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; + if (ra->cfra) { + LOG_A(NR_MAC, "(rnti 0x%04x) CFRA procedure succeeded!\n", UE->rnti); + nr_mac_reset_ul_failure(UE_scheduling_control); + reset_dl_harq_list(UE_scheduling_control); + reset_ul_harq_list(UE_scheduling_control); + process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, UE->CellGroup->rlc_BearerToAddModList); + int ss_type; + // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration in SA + // in NSA (or do-ra) there is no reconfiguration in NR + if (IS_SA_MODE(get_softmodem_params())) + ss_type = NR_SearchSpace__searchSpaceType_PR_common; + else + ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific; + configure_UE_BWP(mac, scc, UE, false, ss_type, -1, -1); + if (!transition_ra_connected_nr_ue(mac, UE)) { + LOG_E(NR_MAC, "cannot add UE %04x: list is full\n", UE->rnti); + delete_nr_ue_data(UE, NULL, &mac->UE_info.uid_allocator); + return; + } + } else { + LOG_D(NR_MAC, "[RAPROC] Received %s:\n", ra->ra_type == RA_2_STEP ? "MsgA-PUSCH" : "Msg3"); + for (uint32_t k = 0; k < sdu_len; k++) { + LOG_D(NR_MAC, "(%i): 0x%x\n", k, sdu[k]); + } + + // 3GPP TS 38.321 Section 5.4.3 Multiplexing and assembly + // Logical channels shall be prioritised in accordance with the following order (highest priority listed first): + // - MAC CE for C-RNTI, or data from UL-CCCH; + // This way, we need to process MAC CE for C-RNTI if RA is active and it is present in the MAC PDU + // Search for MAC CE for C-RNTI + rnti_t crnti = lcid_crnti_lookahead(sdu, sdu_len); + if (crnti != 0) { // 3GPP TS 38.321 Table 7.1-1: RNTI values, RNTI 0x0000: N/A + // Replace the current UE by the UE identified by C-RNTI + NR_UE_info_t *old_UE = find_nr_UE(&mac->UE_info, crnti); + if (!old_UE) { + // The UE identified by C-RNTI no longer exists at the gNB + // Let's abort the current RA, so the UE will trigger a new RA later but using RRCSetupRequest instead. A better + // solution may be implemented + LOG_W(NR_MAC, "No UE found with C-RNTI %04x, ignoring Msg3 to have UE come back with new RA attempt\n", UE->rnti); + nr_release_ra_UE(mac, rnti); + return; + } + // in case UE beam has changed + old_UE->UE_beam_index = UE->UE_beam_index; + // Reset UL failure for old UE + nr_mac_reset_ul_failure(&old_UE->UE_sched_ctrl); + // Reset HARQ processes + reset_dl_harq_list(&old_UE->UE_sched_ctrl); + reset_ul_harq_list(&old_UE->UE_sched_ctrl); + // Trigger RRC Reconfiguration + LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti); + nr_mac_trigger_reconfiguration(mac, old_UE); + nr_release_ra_UE(mac, rnti); + LOG_A(NR_MAC, "%4d.%2d UE %04x: RA with C-RNTI complete\n", frame, slot, crnti); + // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration + configure_UE_BWP(mac, scc, old_UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); + // TODO do we actually need to still process the PDU? + nr_process_mac_pdu(mod_id, old_UE, CC_id, frame, slot, sdu, sdu_len, -1); + return; + } else { + // UE Contention Resolution Identity + // Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4 + // First byte corresponds to R/LCID MAC sub-header + memcpy(ra->cont_res_id, &sdu[1], sizeof(uint8_t) * 6); + } + + // Decode MAC PDU for the correct UE, after checking for MAC CE for C-RNTI + // harq_pid set a non valid value because it is not used in this call + // the function is only called to decode the contention resolution sub-header + nr_process_mac_pdu(mod_id, UE, CC_id, frame, slot, sdu, sdu_len, -1); + + LOG_I(NR_MAC, + "Activating scheduling %s for TC_RNTI 0x%04x (state %s)\n", + ra->ra_type == RA_2_STEP ? "MsgB" : "Msg4", + UE->rnti, + nrra_text[ra->ra_state]); + ra->ra_state = ra->ra_type == RA_2_STEP ? nrRA_MsgB : nrRA_Msg4; + LOG_D(NR_MAC, "TC_RNTI 0x%04x next RA state %s\n", UE->rnti, nrra_text[ra->ra_state]); + return; + } +} + static void _nr_rx_sdu(const module_id_t gnb_mod_idP, const int CC_idP, const frame_t frameP, @@ -677,20 +798,14 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, const uint16_t rssi) { gNB_MAC_INST *gNB_mac = RC.nrmac[gnb_mod_idP]; - const int current_rnti = rntiP; LOG_D(NR_MAC, "rx_sdu for rnti %04x\n", current_rnti); const int target_snrx10 = gNB_mac->pusch_target_snrx10; const int rssi_threshold = gNB_mac->pusch_rssi_threshold; const int pusch_failure_thres = gNB_mac->pusch_failure_thres; - NR_UE_info_t *UE = find_nr_UE(&gNB_mac->UE_info, current_rnti); - bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(gNB_mac, CC_idP, frameP, slotP, current_rnti); - - if (UE && UE_waiting_CFRA_msg3 == false) { - + if (UE) { NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl; - if (sduP) T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP), T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(harq_pid), @@ -729,7 +844,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, UE_scheduling_control->ta_update = timing_advance; UE_scheduling_control->raw_rssi = rssi; UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - (txpower_calc * 10); - if (UE_scheduling_control->tpc0 > 1) LOG_D(NR_MAC, "[UE %04x] %d.%d. PUSCH TPC %d and TA %d pusch_snrx10 %d rssi %d phrx_tx_power %d PHR (1PRB) %d mcs %d, nb_rb %d\n", @@ -747,7 +861,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, NR_UE_ul_harq_t *cur_harq = &UE_scheduling_control->ul_harq_processes[harq_pid]; if (cur_harq->round == 0) - UE->mac_stats.pusch_snrx10 = UE_scheduling_control->pusch_snrx10; + UE->mac_stats.pusch_snrx10 = UE_scheduling_control->pusch_snrx10; LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n",UE->rnti,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update); } else{ @@ -769,15 +883,13 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, if (sduP != NULL) { LOG_D(NR_MAC, "Received PDU at MAC gNB \n"); - UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt = 0; UE_scheduling_control->sched_ul_bytes -= sdu_lenP; if (UE_scheduling_control->sched_ul_bytes < 0) UE_scheduling_control->sched_ul_bytes = 0; nr_process_mac_pdu(gnb_mod_idP, UE, CC_idP, frameP, slotP, sduP, sdu_lenP, harq_pid); - } - else { + } else { if (ul_cqi == 0xff || ul_cqi <= 128) { UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt++; UE->mac_stats.ulsch_DTX++; @@ -791,186 +903,9 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); } } - } else if (sduP) { - - bool no_sig = true; - for (uint32_t k = 0; k < sdu_lenP; k++) { - if (sduP[k] != 0) { - no_sig = false; - break; - } - } - - T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP), - T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(-1) /* harq_pid */, - T_BUFFER(sduP, sdu_lenP)); - - /* we don't know this UE (yet). Check whether there is a ongoing RA (Msg 3) - * and check the corresponding UE's RNTI match, in which case we activate - * it. */ - for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) { - NR_RA_t *ra = &gNB_mac->common_channels[CC_idP].ra[i]; - if (ra->ra_type == RA_4_STEP && ra->ra_state != nrRA_WAIT_Msg3) - continue; - - if (no_sig) { - LOG_W(NR_MAC, "Random Access %i ULSCH with no signal\n", i); - handle_msg3_failed_rx(ra, i, gNB_mac->ul_bler.harq_round_max); - continue; - } - if (ra->ra_type == RA_2_STEP) { - // random access pusch with RA-RNTI - if (ra->RA_rnti != current_rnti) { - LOG_E(NR_MAC, "expected TC_RNTI %04x to match current RNTI %04x\n", ra->RA_rnti, current_rnti); - continue; - } - } else { - // random access pusch with TC-RNTI - if (ra->rnti != current_rnti) { - LOG_E(NR_MAC, "expected TC_RNTI %04x to match current RNTI %04x\n", ra->rnti, current_rnti); - - if ((frameP == ra->Msg3_frame) && (slotP == ra->Msg3_slot)) { - LOG_W(NR_MAC, - "Random Access %i failed at state %s (TC_RNTI %04x RNTI %04x)\n", - i, - nrra_text[ra->ra_state], - ra->rnti, - current_rnti); - nr_clear_ra_proc(ra); - } - - continue; - } - } - - UE = UE ? UE : add_new_nr_ue(gNB_mac, ra->rnti, ra->CellGroup); - if (!UE) { - LOG_W(NR_MAC, - "Random Access %i discarded at state %s (TC_RNTI %04x RNTI %04x): max number of users achieved!\n", - i, - nrra_text[ra->ra_state], - ra->rnti, - current_rnti); - - nr_clear_ra_proc(ra); - return; - } - - UE->UE_beam_index = ra->beam_id; - - // re-initialize ta update variables after RA procedure completion - UE->UE_sched_ctrl.ta_frame = frameP; - - LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frameP, slotP, current_rnti); - - NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl; - if (ul_cqi != 0xff) { - UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30, UE_scheduling_control->sched_pusch.phr_txpower_calc); - UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - UE_scheduling_control->sched_pusch.phr_txpower_calc * 10; - } - if (timing_advance != 0xffff) - UE_scheduling_control->ta_update = timing_advance; - UE_scheduling_control->raw_rssi = rssi; - LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n", UE->rnti, UE_scheduling_control->tpc0, UE_scheduling_control->ta_update); - if (ra->cfra) { - LOG_A(NR_MAC, "(rnti 0x%04x) CFRA procedure succeeded!\n", ra->rnti); - nr_mac_reset_ul_failure(UE_scheduling_control); - reset_dl_harq_list(UE_scheduling_control); - reset_ul_harq_list(UE_scheduling_control); - process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, ra->CellGroup->rlc_BearerToAddModList); - nr_clear_ra_proc(ra); - } else { - LOG_D(NR_MAC, "[RAPROC] Received %s:\n", ra->ra_type == RA_2_STEP ? "MsgA-PUSCH" : "Msg3"); - for (uint32_t k = 0; k < sdu_lenP; k++) { - LOG_D(NR_MAC, "(%i): 0x%x\n", k, sduP[k]); - } - - // 3GPP TS 38.321 Section 5.4.3 Multiplexing and assembly - // Logical channels shall be prioritised in accordance with the following order (highest priority listed first): - // - MAC CE for C-RNTI, or data from UL-CCCH; - // This way, we need to process MAC CE for C-RNTI if RA is active and it is present in the MAC PDU - // Search for MAC CE for C-RNTI - rnti_t crnti = lcid_crnti_lookahead(sduP, sdu_lenP); - if (crnti != 0) { // 3GPP TS 38.321 Table 7.1-1: RNTI values, RNTI 0x0000: N/A - // this UE is the one identified by the RNTI in sduP - ra->rnti = crnti; - // Remove UE context just created after Msg.3 in some milliseconds as the UE is one already known (not now, as the UE - // context is still needed for the moment) - nr_mac_trigger_release_timer(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); - - // Replace the current UE by the UE identified by C-RNTI - UE = find_nr_UE(&gNB_mac->UE_info, crnti); - if (!UE) { - // The UE identified by C-RNTI no longer exists at the gNB - // Let's abort the current RA, so the UE will trigger a new RA later but using RRCSetupRequest instead. A better - // solution may be implemented - LOG_W(NR_MAC, "No UE found with C-RNTI %04x, ignoring Msg3 to have UE come back with new RA attempt\n", ra->rnti); - mac_remove_nr_ue(gNB_mac, ra->rnti); - nr_clear_ra_proc(ra); - return; - } - - // The UE identified by C-RNTI still exists at the gNB - // Reset Msg4_ACKed to not schedule ULSCH and DLSCH before RRC Reconfiguration - UE->Msg4_MsgB_ACKed = false; - nr_mac_reset_ul_failure(&UE->UE_sched_ctrl); - // Reset HARQ processes - reset_dl_harq_list(&UE->UE_sched_ctrl); - reset_ul_harq_list(&UE->UE_sched_ctrl); - - // Switch to BWP where RA is configured, typically in the InitialBWP - // At this point, UE already switched and triggered RA in that BWP, need to do BWP switching also at gNB for C-RNTI - if (ra->DL_BWP.bwp_id != UE->current_DL_BWP.bwp_id || ra->UL_BWP.bwp_id != UE->current_UL_BWP.bwp_id) { - LOG_D(NR_MAC, "UE %04x Switch BWP from %ld to BWP id %ld\n", UE->rnti, UE->current_DL_BWP.bwp_id, ra->DL_BWP.bwp_id); - NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_idP].ServingCellConfigCommon; - configure_UE_BWP(gNB_mac, scc, &UE->UE_sched_ctrl, NULL, UE, ra->DL_BWP.bwp_id, ra->UL_BWP.bwp_id); - } - - if (UE->reconfigCellGroup) { - // Nothing to do - // A RRCReconfiguration message should be already pending (for example, an ongoing RRCReestablishment), and it will be - // transmitted in Msg4 - } else { - // Trigger RRC Reconfiguration - LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", UE->rnti); - nr_mac_trigger_reconfiguration(gNB_mac, UE); - } - } else { - // UE Contention Resolution Identity - // Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4 - // First byte corresponds to R/LCID MAC sub-header - memcpy(ra->cont_res_id, &sduP[1], sizeof(uint8_t) * 6); - } - - // Decode MAC PDU for the correct UE, after checking for MAC CE for C-RNTI - // harq_pid set a non valid value because it is not used in this call - // the function is only called to decode the contention resolution sub-header - nr_process_mac_pdu(gnb_mod_idP, UE, CC_idP, frameP, slotP, sduP, sdu_lenP, -1); - - LOG_I(NR_MAC, - "Activating scheduling %s for TC_RNTI 0x%04x (state %s)\n", - ra->ra_type == RA_2_STEP ? "MsgB" : "Msg4", - ra->rnti, - nrra_text[ra->ra_state]); - ra->ra_state = ra->ra_type == RA_2_STEP ? nrRA_MsgB : nrRA_Msg4; - LOG_D(NR_MAC, "TC_RNTI 0x%04x next RA state %s\n", ra->rnti, nrra_text[ra->ra_state]); - return; - } - } - } else { - for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) { - NR_RA_t *ra = &gNB_mac->common_channels[CC_idP].ra[i]; - if (ra->ra_state != nrRA_WAIT_Msg3) - continue; - - if((frameP!=ra->Msg3_frame) || (slotP!=ra->Msg3_slot)) - continue; - - if (ul_cqi != 0xff) - ra->msg3_TPC = nr_get_tpc(target_snrx10, ul_cqi, 30, 0); - - handle_msg3_failed_rx(ra, i, gNB_mac->ul_bler.harq_round_max); - } + handle_nr_ul_harq(gNB_mac, UE, frameP, slotP, current_rnti, harq_pid, sduP == NULL); + } else { + nr_rx_ra_sdu(gnb_mod_idP, CC_idP, frameP, slotP, current_rnti, sduP, sdu_lenP, timing_advance, ul_cqi, rssi); } } @@ -1891,7 +1826,7 @@ static void pf_ul(module_id_t module_id, UE_iterator(UE_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - if (!UE->Msg4_MsgB_ACKed || sched_ctrl->ul_failure) + if (sched_ctrl->ul_failure) continue; LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti); @@ -2012,7 +1947,7 @@ static void pf_ul(module_id_t module_id, continue; } - sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1; + sched_pusch->nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); sched_pusch->time_domain_allocation = get_ul_tda(nrmac, sched_frame, sched_slot); sched_pusch->tda_info = get_ul_tda_info(current_BWP, sched_ctrl->coreset->controlResourceSetId, @@ -2162,7 +2097,7 @@ static void pf_ul(module_id_t module_id, - sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1; + sched_pusch->nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); sched_pusch->time_domain_allocation = get_ul_tda(nrmac, sched_frame, sched_slot); sched_pusch->tda_info = get_ul_tda_info(current_BWP, sched_ctrl->coreset->controlResourceSetId, @@ -2279,7 +2214,7 @@ static bool nr_ulsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s { gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; // no UEs - if (nr_mac->UE_info.list[0] == NULL) + if (nr_mac->UE_info.connected_ue_list[0] == NULL) return false; NR_COMMON_channels_t *cc = nr_mac->common_channels; @@ -2308,7 +2243,7 @@ static bool nr_ulsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); /* proportional fair scheduling algorithm */ - pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.list, max_sched_ues, num_beams, len); + pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.connected_ue_list, max_sched_ues, num_beams, len); return true; } @@ -2369,7 +2304,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, slot_t slot, nfapi_ NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon; NR_UEs_t *UE_info = &nr_mac->UE_info; - UE_iterator( UE_info->list, UE) { + UE_iterator(UE_info->connected_ue_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; if (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) continue; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 8b403f9e86..3ac09ce98a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -60,11 +60,10 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac); bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_sib_msg_t cu_sib[num_cu_sib]); bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup); -bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup); - +void nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, NR_UE_info_t *UE); +bool add_new_UE_RA(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs); -bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup); int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots); int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info); @@ -135,8 +134,6 @@ void nr_initiate_ra_proc(module_id_t module_idP, int16_t timing_offset, uint32_t preamble_power); -void nr_clear_ra_proc(NR_RA_t *ra); - int nr_allocate_CCEs(int module_idP, int CC_idP, frame_t frameP, slot_t slotP, int test_only); void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP); @@ -273,11 +270,6 @@ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, NR_SearchSpace_t *ss, NR_SearchSpace__searchSpaceType_PR ss_type); -/* find a search space within a BWP */ -NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc, - NR_BWP_DownlinkDedicated_t *bwp_Dedicated, - NR_SearchSpace__searchSpaceType_PR target_ss); - long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList, int time_domain_assignment, int mu, @@ -310,21 +302,23 @@ void remove_nr_list(NR_list_t *listP, int id); void add_tail_nr_list(NR_list_t *listP, int id); void add_front_nr_list(NR_list_t *listP, int id); void remove_front_nr_list(NR_list_t *listP); - +void nr_release_ra_UE(gNB_MAC_INST *mac, rnti_t rnti); NR_UE_info_t * find_nr_UE(NR_UEs_t* UEs, rnti_t rntiP); - +NR_UE_info_t *find_ra_UE(NR_UEs_t *UEs, rnti_t rntiP); +void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_allocator_t *uia); void configure_UE_BWP(gNB_MAC_INST *nr_mac, NR_ServingCellConfigCommon_t *scc, - NR_UE_sched_ctrl_t *sched_ctrl, - NR_RA_t *ra, NR_UE_info_t *UE, + bool is_RA, + int target_ss, int dl_bwp_switch, int ul_bwp_switch); -NR_UE_info_t* add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup); - +bool transition_ra_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); +bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); +void nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, NR_UE_info_t *UE, bool success); void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti); - +NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup); int nr_get_default_pucch_res(int pucch_ResourceCommon); int nr_write_ce_dlsch_pdu(module_id_t module_idP, @@ -362,12 +356,6 @@ void reset_dl_harq_list(NR_UE_sched_ctrl_t *sched_ctrl); void reset_ul_harq_list(NR_UE_sched_ctrl_t *sched_ctrl); -void handle_nr_ul_harq(const int CC_idP, - module_id_t mod_id, - frame_t frame, - slot_t slot, - const nfapi_nr_crc_t *crc_pdu); - uint8_t *allocate_transportBlock_buffer(byte_array_t *tb, uint32_t needed); void free_transportBlock_buffer(byte_array_t *tb); @@ -392,9 +380,11 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac, uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx); uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format); +int get_ul_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format); void free_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl); - +bool add_UE_to_list(int list_size, NR_UE_info_t *list[list_size], NR_UE_info_t *UE); +NR_UE_info_t *remove_UE_from_list(int list_size, NR_UE_info_t *list[list_size], rnti_t rnti); int get_dl_tda(const gNB_MAC_INST *nrmac, int slot); int get_ul_tda(gNB_MAC_INST *nrmac, int frame, int slot); @@ -430,7 +420,6 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, int ul_buffer_index(int frame, int slot, int slots_per_frame, int size); void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP); - void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, gNB_MAC_INST *mac); int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx); NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame); @@ -467,11 +456,13 @@ void process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl, bool nr_mac_add_lcid(NR_UE_sched_ctrl_t *sched_ctrl, const nr_lc_config_t *c); bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid); -bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti); +bool nr_mac_get_new_rnti(NR_UEs_t *UEs, rnti_t *rnti); void nr_mac_update_pdcch_closed_loop_adjust(NR_UE_sched_ctrl_t *sched_ctrl, bool feedback_not_detected); void prepare_du_configuration_update(gNB_MAC_INST *mac, f1ap_served_cell_info_t *info, NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1); + +void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group); #endif /*__LAYER2_NR_MAC_PROTO_H__*/ 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 32943097ba..317b030e4a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -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" @@ -105,7 +106,7 @@ void du_clear_all_ue_states() gNB_MAC_INST *mac = RC.nrmac[0]; NR_SCHED_LOCK(&mac->sched_lock); - NR_UE_info_t *UE = *mac->UE_info.list; + NR_UE_info_t *UE = *mac->UE_info.connected_ue_list; instance_t f1inst = get_f1_gtp_instance(); @@ -116,7 +117,7 @@ void du_clear_all_ue_states() if (du_exists_f1_ue_data(rnti)) du_remove_f1_ue_data(rnti); newGtpuDeleteAllTunnels(f1inst, rnti); - UE = *mac->UE_info.list; + UE = *mac->UE_info.connected_ue_list; } NR_SCHED_UNLOCK(&mac->sched_lock); } @@ -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,43 +522,74 @@ 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; - 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; + 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); + cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc); + // 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 - UE->Msg4_MsgB_ACKed = true; + AssertFatal(cellGroupConfig != NULL, "out of memory\n"); 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 */ + 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 = { @@ -523,9 +603,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) { @@ -533,15 +615,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"); @@ -569,18 +657,23 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) nr_rlc_srb_recv_sdu(req->gNB_DU_ue_id, id, req->rrc_container, req->rrc_container_length); } + 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 - NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; + // 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) { asn1cCallocOne(addmod->list.array[i]->reestablishRLC, NR_RLC_BearerConfig__reestablishRLC_true); + for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { + nr_lc_config_t *lc_config = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); + nr_rlc_reestablish_entity(UE->rnti, lc_config->lcid); + } } } @@ -593,7 +686,10 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) AssertFatal(enc_rval.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval.failed_type->name); resp.du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded + 7) >> 3; - nr_mac_prepare_cellgroup_update(mac, UE, new_CellGroup); + ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); + UE->CellGroup = new_CellGroup; + 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); @@ -664,9 +760,15 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) nr_rlc_srb_recv_sdu(req->gNB_DU_ue_id, id, req->rrc_container, req->rrc_container_length); } + NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; if (req->ReconfigComplOutcome != RRCreconf_info_not_present && req->ReconfigComplOutcome != RRCreconf_success) { LOG_E(NR_MAC, "RRC reconfiguration outcome unsuccessful, but no rollback mechanism implemented to come back to old configuration\n"); + } else if (req->ReconfigComplOutcome == RRCreconf_success) { + LOG_I(NR_MAC, "DU received confirmation of successful RRC Reconfiguration\n"); + // we re-configure the BWP to apply the CellGroup and to use UE specific Search Space with DCIX1 + nr_mac_clean_cellgroup(UE->CellGroup); + configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1); } if (ue_cap != NULL) { @@ -674,7 +776,6 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->capability); UE->capability = ue_cap; LOG_I(NR_MAC, "UE %04x: received capabilities, updating CellGroupConfig\n", UE->rnti); - NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc); } @@ -692,7 +793,9 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) AssertFatal(enc_rval.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval.failed_type->name); resp.du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded + 7) >> 3; - nr_mac_prepare_cellgroup_update(mac, UE, new_CellGroup); + 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); } else { ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, new_CellGroup); // we actually don't need it } @@ -759,13 +862,6 @@ void ue_context_modification_refuse(const f1ap_ue_context_modif_refuse_t *refuse return; } - const int CC_id = 0; - NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; - for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { - NR_RA_t *ra = &cc->ra[i]; - if (ra->rnti == UE->rnti) - nr_clear_ra_proc(ra); - } NR_SCHED_UNLOCK(&mac->sched_lock); f1ap_ue_context_release_req_t request = { @@ -822,6 +918,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) pthread_mutex_lock(&mac->sched_lock); /* check first that the scheduler knows such UE */ NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, dl_rrc->gNB_DU_ue_id); + UE = UE ? UE : find_ra_UE(&mac->UE_info, dl_rrc->gNB_DU_ue_id); if (UE == NULL) { LOG_E(MAC, "ERROR: unknown UE with RNTI %04x, ignoring DL RRC Message Transfer\n", dl_rrc->gNB_DU_ue_id); pthread_mutex_unlock(&mac->sched_lock); @@ -836,24 +933,13 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) DevAssert(success); } - if (UE->expect_reconfiguration && dl_rrc->srb_id == 1) { - /* we expected a reconfiguration, and this is on DCCH. We assume this is - * the reconfiguration: nr_mac_prepare_cellgroup_update() already stored - * the CellGroupConfig. Below, we trigger a timer, and the CellGroupConfig - * will be applied after its expiry in nr_mac_apply_cellgroup().*/ - NR_SCHED_LOCK(&mac->sched_lock); - int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs); - nr_mac_interrupt_ue_transmission(mac, UE, FOLLOW_INSYNC_RECONFIG, delay); - NR_SCHED_UNLOCK(&mac->sched_lock); - UE->expect_reconfiguration = false; - /* Re-establish RLC for all remaining bearers */ - if (UE->reestablish_rlc) { - for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { - nr_lc_config_t *lc_config = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); - nr_rlc_reestablish_entity(dl_rrc->gNB_DU_ue_id, lc_config->lcid); - } - UE->reestablish_rlc = false; + if (UE->reestablish_rlc && dl_rrc->srb_id == 1) { + // we expected a reconfiguration to re-establish RLC, and this is on DCCH. We assume this is the reconfiguration. + for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { + nr_lc_config_t *lc_config = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); + nr_rlc_reestablish_entity(dl_rrc->gNB_DU_ue_id, lc_config->lcid); } + UE->reestablish_rlc = false; } if (dl_rrc->old_gNB_DU_ue_id != NULL) { @@ -870,28 +956,25 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) * from the current configuration. Also, expect the reconfiguration from * the CU, so save the old UE's CellGroup for the new UE */ UE->CellGroup->spCellConfig = NULL; - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; uid_t temp_uid = UE->uid; UE->uid = oldUE->uid; oldUE->uid = temp_uid; - configure_UE_BWP(mac, scc, sched_ctrl, NULL, UE, -1, -1); for (int i = 1; i < seq_arr_size(&oldUE->UE_sched_ctrl.lc_config); ++i) { const nr_lc_config_t *c = seq_arr_at(&oldUE->UE_sched_ctrl.lc_config, i); nr_mac_add_lcid(&UE->UE_sched_ctrl, c); } - - nr_mac_prepare_cellgroup_update(mac, UE, oldUE->CellGroup); + ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); + UE->CellGroup = oldUE->CellGroup; oldUE->CellGroup = NULL; mac_remove_nr_ue(mac, *dl_rrc->old_gNB_DU_ue_id); pthread_mutex_unlock(&mac->sched_lock); nr_rlc_remove_ue(dl_rrc->gNB_DU_ue_id); nr_rlc_update_id(*dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id); + /* 38.331 clause 5.3.7.4: apply the specified configuration defined in 9.2.1 for SRB1 */ + nr_rlc_reconfigure_entity(dl_rrc->gNB_DU_ue_id, 1, NULL); /* Set flag to trigger RLC re-establishment * for remaining RBs in next RRCReconfiguration */ UE->reestablish_rlc = true; - /* 38.331 clause 5.3.7.4: apply the specified configuration defined in 9.2.1 for SRB1 */ - nr_rlc_reconfigure_entity(dl_rrc->gNB_DU_ue_id, 1, NULL); instance_t f1inst = get_f1_gtp_instance(); if (f1inst >= 0) // we actually use F1-U gtpv1u_update_ue_id(f1inst, *dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id); diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 4d732bb3eb..3137ce0902 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -106,7 +106,7 @@ void *nrmac_stats_thread(void *arg) { } void clear_mac_stats(gNB_MAC_INST *gNB) { - UE_iterator(gNB->UE_info.list, UE) { + UE_iterator(gNB->UE_info.connected_ue_list, UE) { memset(&UE->mac_stats,0,sizeof(UE->mac_stats)); } } @@ -121,7 +121,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset NR_SCHED_ENSURE_LOCKED(&gNB->sched_lock); NR_SCHED_LOCK(&gNB->UE_info.mutex); - UE_iterator(gNB->UE_info.list, UE) { + UE_iterator(gNB->UE_info.connected_ue_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_mac_stats_t *stats = &UE->mac_stats; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; @@ -312,29 +312,6 @@ void mac_top_init_gNB(ngran_node_t node_type, // These should be out of here later if (get_softmodem_params()->usim_test == 0 ) nr_pdcp_layer_init(); - - if(IS_SOFTMODEM_NOS1 && get_softmodem_params()->phy_test) { - // get default noS1 configuration - NR_RadioBearerConfig_t *rbconfig = NULL; - NR_RLC_BearerConfig_t *rlc_rbconfig = NULL; - fill_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig); - - /* Note! previously, in nr_DRB_preconfiguration(), we passed ENB_FLAG_NO - * if ENB_NAS_USE_TUN was *not* set. It seems to me that we could not set - * this flag anywhere in the code, hence we would always configure PDCP - * with ENB_FLAG_NO in nr_DRB_preconfiguration(). This makes sense for - * noS1, because the result of passing ENB_FLAG_NO to PDCP is that PDCP - * will output the packets at a local interface, which is in line with - * the noS1 mode. Hence, below, we simply hardcode ENB_FLAG_NO */ - // 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); - } - } else { RC.nrmac = NULL; } @@ -359,9 +336,12 @@ void mac_top_destroy_gNB(gNB_MAC_INST *mac) ASN_STRUCT_FREE(asn_DEF_NR_ServingCellConfig, cc->pre_ServingCellConfig); ASN_STRUCT_FREE(asn_DEF_NR_ServingCellConfigCommon, cc->ServingCellConfigCommon); NR_UEs_t *UE_info = &mac->UE_info; - for (int i = 0; i < sizeofArray(UE_info->list); ++i) - if (UE_info->list[i]) - delete_nr_ue_data(UE_info->list[i], cc, &UE_info->uid_allocator); + for (int i = 0; i < sizeofArray(UE_info->connected_ue_list); ++i) + if (UE_info->connected_ue_list[i]) + delete_nr_ue_data(UE_info->connected_ue_list[i], cc, &UE_info->uid_allocator); + for (int i = 0; i < sizeofArray(UE_info->access_ue_list); ++i) + if (UE_info->access_ue_list[i]) + delete_nr_ue_data(UE_info->access_ue_list[i], cc, &UE_info->uid_allocator); } void nr_mac_send_f1_setup_req(void) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 83802182e0..43dcbab20d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -229,8 +229,6 @@ typedef struct { NR_beam_alloc_t Msg3_beam; /// harq_pid used for Msg4 transmission uint8_t harq_pid; - /// UE RNTI allocated during RAR - rnti_t rnti; /// RA RNTI allocated from received PRACH uint16_t RA_rnti; /// MsgB RNTI allocated from received MsgA @@ -251,25 +249,12 @@ typedef struct { int msg3_nbSymb; /// MAC PDU length for Msg4 int mac_pdu_length; - /// RA search space - NR_SearchSpace_t *ra_ss; - /// RA Coreset - NR_ControlResourceSet_t *coreset; - NR_sched_pdcch_t sched_pdcch; - // Beam index - uint8_t beam_id; - /// CellGroup for UE that is to come (NSA is non-null, null for SA) - NR_CellGroupConfig_t *CellGroup; /// Preambles for contention-free access NR_preamble_ue_t preambles; int contention_resolution_timer; nr_ra_type_t ra_type; /// CFRA flag bool cfra; - // BWP for RA - NR_UE_DL_BWP_t DL_BWP; - NR_UE_UL_BWP_t UL_BWP; - NR_UE_ServingCell_Info_t sc_info; } NR_RA_t; /*! \brief gNB common channels */ @@ -289,8 +274,6 @@ typedef struct { /// used for otherSIB data uint8_t other_sib_bcch_pdu[2][NR_MAX_SIB_LENGTH / 8]; int other_sib_bcch_length[2]; - /// Template for RA computations - NR_RA_t ra[NR_NB_RA_PROC_MAX]; /// VRB map for common channels uint16_t vrb_map[MAX_NUM_BEAM_PERIODS][275]; /// VRB map for common channels and PUSCH, dynamically allocated because @@ -654,7 +637,6 @@ typedef struct { int pusch_snrx10; int pucch_snrx10; uint16_t ul_rssi; - uint8_t current_harq_pid; int pusch_consecutive_dtx_cnt; int pucch_consecutive_dtx_cnt; bool ul_failure; @@ -761,27 +743,25 @@ typedef struct { NR_mac_stats_t mac_stats; /// currently active CellGroupConfig NR_CellGroupConfig_t *CellGroup; - /// CellGroupConfig that is to be activated after the next reconfiguration - bool expect_reconfiguration; /// reestablishRLC has to be signaled in RRCreconfiguration bool reestablish_rlc; - NR_CellGroupConfig_t *reconfigCellGroup; interrupt_followup_action_t interrupt_action; NR_UE_NR_Capability_t *capability; // UE selected beam index uint8_t UE_beam_index; - bool Msg4_MsgB_ACKed; float ul_thr_ue; float dl_thr_ue; long pdsch_HARQ_ACK_Codebook; bool is_redcap; + NR_RA_t *ra; } NR_UE_info_t; typedef struct { /// scheduling control info // last element always NULL pthread_mutex_t mutex; - NR_UE_info_t *list[MAX_MOBILES_PER_GNB+1]; + NR_UE_info_t *connected_ue_list[MAX_MOBILES_PER_GNB + 1]; + NR_UE_info_t *access_ue_list[NR_NB_RA_PROC_MAX]; // bitmap of CSI-RS already scheduled in current slot int sched_csirs; uid_allocator_t uid_allocator; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 322277c3aa..8dfa57f92b 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -899,12 +899,6 @@ void nr_rlc_remove_ue(int ue_id) nr_rlc_manager_unlock(nr_rlc_ue_manager); } -rlc_op_status_t rrc_rlc_remove_ue (const protocol_ctxt_t* const x) -{ - nr_rlc_remove_ue(x->rntiMaybeUEid); - return RLC_OP_STATUS_OK; -} - bool nr_rlc_update_id(int from_id, int to_id) { nr_rlc_manager_lock(nr_rlc_ue_manager); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index e82a185ba8..2352870ace 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -203,7 +203,6 @@ static void handle_nr_ulsch(NR_UL_IND_t *UL_info) crc->timing_advance, crc->ul_cqi, crc->rssi); - handle_nr_ul_harq(UL_info->CC_id, UL_info->module_id, UL_info->frame, UL_info->slot, crc); } UL_info->rx_ind.number_of_pdus = 0; UL_info->crc_ind.number_crcs = 0; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 131b2694b6..586e2e7628 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -425,32 +425,6 @@ NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, return rbconfig; } -void fill_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig, - NR_RLC_BearerConfig_t **rlc_rbconfig) -{ - /* the EPS bearer ID is arbitrary; the rb_id is 1/the first DRB, it needs to - * match the one in get_DRB_RLC_BearerConfig(). No ciphering is to be - * configured */ - *rbconfig = get_default_rbconfig(10, 1, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master); - AssertFatal(*rbconfig != NULL, "get_default_rbconfig() failed\n"); - /* LCID is 4 because the RLC layer requires it to be 3+rb_id; the rb_id 1 is - * common with get_default_rbconfig() (first RB). We pre-configure RLC UM - * Bi-directional, priority is 1 */ - *rlc_rbconfig = get_DRB_RLC_BearerConfig(4, 1, NR_RLC_Config_PR_um_Bi_Directional, 1); - AssertFatal(*rlc_rbconfig != NULL, "get_DRB_RLC_BearerConfig() failed\n"); -} - -void free_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig, - NR_RLC_BearerConfig_t **rlc_rbconfig) -{ - ASN_STRUCT_FREE(asn_DEF_NR_RadioBearerConfig, *rbconfig); - *rbconfig = NULL; - if (rlc_rbconfig != NULL) { - ASN_STRUCT_FREE(asn_DEF_NR_RLC_BearerConfig, *rlc_rbconfig); - *rlc_rbconfig = NULL; - } -} - //------------------------------------------------------------------------------ int do_RRCSetup(uint8_t *const buffer, size_t buffer_size, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 3d09a65bd0..344659afbb 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -80,11 +80,6 @@ NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, e_NR_CipheringAlgorithm ciphering_algorithm, e_NR_SecurityConfig__keyToUse key_to_use); -void fill_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig, - NR_RLC_BearerConfig_t **rlc_rbconfig); -void free_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig, - NR_RLC_BearerConfig_t **rlc_rbconfig); - int do_RRCSetup(uint8_t *const buffer, size_t buffer_size, const uint8_t transaction_id, 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_config.c b/openair2/RRC/NR/nr_rrc_config.c index 32f0ccae40..ac4f25109e 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -3128,7 +3128,15 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, coreset); - int searchspaceid = 5; + int css_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; + css_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; + css_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; + css_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1; + css_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; + css_num_agg_level_candidates[PDCCH_AGG_LEVEL16] = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; + int searchspaceid = 4; + NR_SearchSpace_t *ss = rrc_searchspace_config(true, searchspaceid, 0, css_num_agg_level_candidates); + searchspaceid = 5; int rrc_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; int num_cces = get_coreset_num_cces(coreset->frequencyDomainResources.buf, coreset->duration); verify_agg_levels(num_cces, @@ -3137,6 +3145,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, searchspaceid, rrc_num_agg_level_candidates); NR_SearchSpace_t *ss2 = rrc_searchspace_config(false, searchspaceid, coreset->controlResourceSetId, rrc_num_agg_level_candidates); + asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss); asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss2); bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, pdsch_AntennaPorts); @@ -3550,23 +3559,14 @@ 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(); secondaryCellGroup->spCellConfig = calloc(1, sizeof(*secondaryCellGroup->spCellConfig)); secondaryCellGroup->spCellConfig->servCellIndex = calloc(1, sizeof(*secondaryCellGroup->spCellConfig->servCellIndex)); *secondaryCellGroup->spCellConfig->servCellIndex = servCellIndex; - secondaryCellGroup->spCellConfig->reconfigurationWithSync = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->reconfigurationWithSync)); - - rnti_t rnti = get_softmodem_params()->phy_test == 1 ? 0x1234 : (taus() & 0xffff); - secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, servingcellconfigcommon); secondaryCellGroup->spCellConfig->rlf_TimersAndConstants = calloc(1, sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants)); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 79d102f9e3..6cee7e6fa4 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -221,9 +221,9 @@ typedef struct gNB_RRC_UE_s { ngap_security_capabilities_t security_capabilities; //NSA block - /* Number of NSA e_rab */ + sctp_assoc_t x2_target_assoc; + int MeNB_ue_x2_id; int nb_of_e_rabs; - /* list of pdu session to be setup by RRC layers */ nr_e_rab_param_t e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB]; uint32_t nsa_gtp_teid[S1AP_MAX_E_RAB]; transport_layer_addr_t nsa_gtp_addrs[S1AP_MAX_E_RAB]; @@ -238,7 +238,7 @@ typedef struct gNB_RRC_UE_s { uint32_t ue_rrc_inactivity_timer; uint32_t ue_reestablishment_counter; uint32_t ue_reconfiguration_counter; - + bool ongoing_reconfiguration; bool an_release; // flag if core requested UE release /* NGUEContextSetup might come with PDU sessions, but setup needs to be diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index dc5e77bbc5..c5627b6e55 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -41,17 +41,13 @@ #define NR_MAX_SUPPORTED_DL_LAYERS 4 -void rrc_parse_ue_capabilities(gNB_RRC_INST *rrc,NR_UE_CapabilityRAT_ContainerList_t *UE_CapabilityRAT_ContainerList, x2ap_ENDC_sgnb_addition_req_t *m, NR_CG_ConfigInfo_IEs_t * cg_config_info); +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); -void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2ap_ENDC_sgnb_addition_req_t *m); - -void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti); void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p); -NR_RRCReconfiguration_IEs_t *get_default_reconfig(const NR_CellGroupConfig_t *secondaryCellGroup); - -NR_CG_Config_t *generate_CG_Config(const NR_RRCReconfiguration_t *reconfig, const NR_RadioBearerConfig_t *rbconfig); - int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo, x2ap_ENDC_sgnb_addition_req_t *m); void rrc_gNB_generate_SecurityModeCommand(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 8f6be46f19..db45c2b0c3 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -255,41 +255,14 @@ void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *c RB_INIT(&rrc->cuups); RB_INIT(&rrc->dus); rrc->configuration = *configuration; - - if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) { - AssertFatal(NODE_IS_MONOLITHIC(rrc->node_type), "phy_test and do_ra only work in monolithic\n"); - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_allocate_new_ue_context(rrc); - LOG_I(NR_RRC,"Adding new user (%p)\n",ue_context_p); - if (!NODE_IS_CU(rrc->node_type)) { - rrc_add_nsa_user(rrc,ue_context_p,NULL); - } - } } static void rrc_gNB_process_AdditionRequestInformation(const module_id_t gnb_mod_idP, x2ap_ENDC_sgnb_addition_req_t *m) { - 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, - (uint8_t *)m->rrc_buffer, - (int) m->rrc_buffer_size);//m->rrc_buffer_size); - gNB_RRC_INST *rrc=RC.nrrrc[gnb_mod_idP]; - - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - AssertFatal(1==0,"NR_UL_DCCH_MESSAGE decode error\n"); - // free the memory - SEQUENCE_free(&asn_DEF_NR_CG_ConfigInfo, cg_configinfo, 1); - return; - } - - xer_fprint(stdout,&asn_DEF_NR_CG_ConfigInfo, cg_configinfo); - // recreate enough of X2 EN-DC Container - AssertFatal(cg_configinfo->criticalExtensions.choice.c1->present == NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo, - "ueCapabilityInformation not present\n"); - parse_CG_ConfigInfo(rrc,cg_configinfo,m); - LOG_I(NR_RRC, "Successfully parsed CG_ConfigInfo of size %zu bits. (%zu bytes)\n", - dec_rval.consumed, (dec_rval.consumed +7/8)); + 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"); + sctp_assoc_t assoc_id = -1; // monolithic gNB + rrc_add_nsa_user(rrc, m, assoc_id); } //----------------------------------------------------------------------------- @@ -1145,6 +1118,7 @@ int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int { uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[xid] = RRC_DEDICATED_RECONF; + ue_p->ongoing_reconfiguration = true; NR_CellGroupConfig_t *masterCellGroup = ue_p->masterCellGroup; if (dl_bwp_id > 0) { @@ -1237,6 +1211,7 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, UE->establishment_cause = rrcSetupRequest->establishmentCause; UE->nr_cellid = msg->nr_cellid; UE->masterCellGroup = cellGroupConfig; + UE->ongoing_reconfiguration = false; activate_srb(UE, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); } @@ -1804,6 +1779,7 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U { uint8_t xid = reconfig_complete->rrc_TransactionIdentifier; UE->ue_reconfiguration_counter++; + UE->ongoing_reconfiguration = false; switch (UE->xids[xid]) { case RRC_PDUSESSION_RELEASE: { @@ -1854,6 +1830,15 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U UE->ho_context->target->ho_success(rrc, UE); nr_rrc_finalize_ho(UE); } + + f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); + f1ap_ue_context_modif_req_t ue_context_modif_req = { + .gNB_CU_ue_id = UE->rrc_ue_id, + .gNB_DU_ue_id = ue_data.secondary_ue, + .ReconfigComplOutcome = RRCreconf_success, + }; + rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); } static void rrc_gNB_generate_UECapabilityEnquiry(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue) @@ -2044,16 +2029,27 @@ void rrc_gNB_process_initial_ul_rrc_message(sctp_assoc_t assoc_id, const f1ap_in ASN_STRUCT_FREE(asn_DEF_NR_UL_CCCH_Message, ul_ccch_msg); } +static void rrc_gNB_trigger_nsa_release(module_id_t mod_id, int ue_id) +{ + gNB_RRC_INST *rrc = RC.nrrrc[mod_id]; + rrc_gNB_ue_context_t *ue_context = rrc_gNB_get_ue_context(rrc, ue_id); + if (!ue_context) { + LOG_E(NR_RRC, "could not find UE for ID %d\n", ue_id); + return; + } + rrc_release_nsa_user(rrc, ue_context); +} + void rrc_gNB_process_release_request(const module_id_t gnb_mod_idP, x2ap_ENDC_sgnb_release_request_t *m) { - gNB_RRC_INST *rrc = RC.nrrrc[gnb_mod_idP]; - rrc_remove_nsa_user(rrc, m->rnti); + /* it's not the RNTI, it's the UE ID ... */ + rrc_gNB_trigger_nsa_release(gnb_mod_idP, m->rnti); } void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC_dc_overall_timeout_t *m) { - gNB_RRC_INST *rrc = RC.nrrrc[gnb_mod_idP]; - rrc_remove_nsa_user(rrc, m->rnti); + /* it's not the RNTI, it's the UE ID ... */ + rrc_gNB_trigger_nsa_release(gnb_mod_idP, m->rnti); } /* \brief fill E1 bearer modification's DRB from F1 DRB @@ -2171,6 +2167,11 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); + if (!IS_SA_MODE(get_softmodem_params())) { + rrc_add_nsa_user_resp(rrc, UE, resp); + return; + } + if (resp->drbs_to_be_setup_length > 0) { int num_drb = get_number_active_drbs(UE); DevAssert(num_drb == 0 || num_drb == resp->drbs_to_be_setup_length); @@ -2417,7 +2418,8 @@ static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_ xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); /* trigger reconfiguration */ - nr_rrc_reconfiguration_req(rrc, UE, 0, 0); + if (!UE->ongoing_reconfiguration) + nr_rrc_reconfiguration_req(rrc, UE, 0, 0); return; } LOG_W(RRC, diff --git a/openair2/RRC/NR/rrc_gNB_GTPV1U.c b/openair2/RRC/NR/rrc_gNB_GTPV1U.c deleted file mode 100644 index 79882d58f3..0000000000 --- a/openair2/RRC/NR/rrc_gNB_GTPV1U.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file rrc_gNB_GTPV1U.c - * \brief rrc GTPV1U procedures for gNB - * \author Lionel GAUTHIER, Panos MATZAKOS - * \version 1.0 - * \company Eurecom - * \email: lionel.gauthier@eurecom.fr, panagiotis.matzakos@eurecom.fr - */ - -#include "openair2/RRC/NR/rrc_gNB_GTPV1U.h" -#include "LOG/log.h" -#include "RRC/NR/nr_rrc_defs.h" -#include "common/ran_context.h" -#include "openair2/RRC/NR/rrc_gNB_UE_context.h" -#include "rrc_defs.h" -#include "rrc_eNB_GTPV1U.h" -#include "s1ap_messages_types.h" - -int rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(gNB_RRC_UE_t *ue, - const gtpv1u_enb_create_tunnel_resp_t *const create_tunnel_resp_pP, - uint8_t *inde_list) -{ - if (!create_tunnel_resp_pP) { - LOG_E(NR_RRC, "create_tunnel_resp_pP error\n"); - return -1; - } - - for (int i = 0; i < create_tunnel_resp_pP->num_tunnels; i++) { - ue->nsa_gtp_teid[inde_list[i]] = create_tunnel_resp_pP->enb_S1u_teid[i]; - ue->nsa_gtp_addrs[inde_list[i]] = create_tunnel_resp_pP->enb_addr; - ue->nsa_gtp_ebi[inde_list[i]] = create_tunnel_resp_pP->eps_bearer_id[i]; - LOG_I(RRC, - "UE %d: rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP tunnel (%u, %u) bearer UE context index %u, msg index %u, id %u, gtp " - "addr len %d \n", - ue->rrc_ue_id, - create_tunnel_resp_pP->enb_S1u_teid[i], - ue->nsa_gtp_teid[inde_list[i]], - inde_list[i], - i, - create_tunnel_resp_pP->eps_bearer_id[i], - create_tunnel_resp_pP->enb_addr.length); - } - - return 0; -} diff --git a/openair2/RRC/NR/rrc_gNB_GTPV1U.h b/openair2/RRC/NR/rrc_gNB_GTPV1U.h deleted file mode 100644 index 60a6c0c5b5..0000000000 --- a/openair2/RRC/NR/rrc_gNB_GTPV1U.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file rrc_gNB_GTPV1U.h - * \brief rrc GTPV1U procedures for gNB - * \author Lionel GAUTHIER, Panos MATZAKOS - * \version 1.0 - * \company Eurecom - * \email: lionel.gauthier@eurecom.fr, panagiotis.matzakos@eurecom.fr - */ - -#ifndef RRC_GNB_GTPV1U_H_ -#define RRC_GNB_GTPV1U_H_ - -#include -#include "openair2/RRC/NR/nr_rrc_defs.h" -#include "gtpv1_u_messages_types.h" - -int rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(gNB_RRC_UE_t *ue, - const gtpv1u_enb_create_tunnel_resp_t *const create_tunnel_resp_pP, - uint8_t *inde_list); - -#endif diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index d6e025309a..8aec9a634b 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -437,11 +437,17 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) if (rrc->node_name != NULL) resp.gNB_CU_name = strdup(rrc->node_name); rrc->mac_rrc.f1_setup_response(assoc_id, &resp); + + /* 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, 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; @@ -451,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; @@ -460,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_internode.c b/openair2/RRC/NR/rrc_gNB_internode.c deleted file mode 100644 index 843eaca250..0000000000 --- a/openair2/RRC/NR/rrc_gNB_internode.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file rrc_gNB_internode.c - * \brief rrc internode procedures for gNB - * \author Raymond Knopp - * \date 2019 - * \version 1.0 - * \company Eurecom - * \email: raymond.knopp@eurecom.fr - */ -#ifndef RRC_GNB_INTERNODE_C -#define RRC_GNB_INTERNODE_C - -#include -#include -#include -#include "OCTET_STRING.h" -#include "RRC/NR/nr_rrc_proto.h" -#include "T.h" -#include "asn_codecs.h" -#include "assertions.h" -#include "common/utils/T/T.h" -#include "constr_TYPE.h" -#include "executables/softmodem-common.h" -#include "nr_rrc_defs.h" -#include "uper_decoder.h" -#include "uper_encoder.h" -#include "x2ap_messages_types.h" - -int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo, x2ap_ENDC_sgnb_addition_req_t *m) { - if (CG_ConfigInfo->criticalExtensions.present == NR_CG_ConfigInfo__criticalExtensions_PR_c1) { - if (CG_ConfigInfo->criticalExtensions.choice.c1) { - if (CG_ConfigInfo->criticalExtensions.choice.c1->present == NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo) { - NR_CG_ConfigInfo_IEs_t *cg_ConfigInfo = CG_ConfigInfo->criticalExtensions.choice.c1->choice.cg_ConfigInfo; - - if (cg_ConfigInfo->ue_CapabilityInfo) { - // Decode UE-CapabilityRAT-ContainerList - NR_UE_CapabilityRAT_ContainerList_t *UE_CapabilityRAT_ContainerList=NULL; - UE_CapabilityRAT_ContainerList = calloc(1,sizeof(NR_UE_CapabilityRAT_ContainerList_t)); - asn_dec_rval_t dec_rval = uper_decode(NULL, - &asn_DEF_NR_UE_CapabilityRAT_ContainerList, - (void **)&UE_CapabilityRAT_ContainerList, - cg_ConfigInfo->ue_CapabilityInfo->buf, - cg_ConfigInfo->ue_CapabilityInfo->size, 0, 0); - - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - AssertFatal(1==0,"[InterNode] Failed to decode NR_UE_CapabilityRAT_ContainerList (%zu bits), size of OCTET_STRING %lu\n", - dec_rval.consumed, cg_ConfigInfo->ue_CapabilityInfo->size); - } - - rrc_parse_ue_capabilities(rrc,UE_CapabilityRAT_ContainerList, m,cg_ConfigInfo); - } - - if (cg_ConfigInfo->candidateCellInfoListMN) AssertFatal(1==0,"Can't handle candidateCellInfoListMN yet\n"); - } else AssertFatal(1==0,"c1 extension is not cg_ConfigInfo, returning\n"); - } else { - LOG_E(RRC,"c1 extension not found, returning\n"); - return(-1); - } - } else { - LOG_E(RRC,"Ignoring unknown CG_ConfigInfo extensions\n"); - return(-1); - } - - return(0); -} - -NR_CG_Config_t *generate_CG_Config(const NR_RRCReconfiguration_t *reconfig, const NR_RadioBearerConfig_t *rbconfig) -{ - NR_CG_Config_t *cg_Config = calloc(1, sizeof(*cg_Config)); - cg_Config->criticalExtensions.present = NR_CG_Config__criticalExtensions_PR_c1; - cg_Config->criticalExtensions.choice.c1 = calloc(1,sizeof(*cg_Config->criticalExtensions.choice.c1)); - cg_Config->criticalExtensions.choice.c1->present = NR_CG_Config__criticalExtensions__c1_PR_cg_Config; - cg_Config->criticalExtensions.choice.c1->choice.cg_Config = calloc(1,sizeof(NR_CG_Config_IEs_t)); - char buffer[1024]; - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_RRCReconfiguration, NULL, (void *)reconfig, buffer, 1024); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig = calloc(1,sizeof(OCTET_STRING_t)); - OCTET_STRING_fromBuf(cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig, - (const char *)buffer, - (enc_rval.encoded+7)>>3); - - FILE *fd; // file to be generated for nr-ue - if (get_softmodem_params()->phy_test==1 || get_softmodem_params()->do_ra > 0) { - // This is for phytest only, emulate first X2 message if uecap.raw file is present - LOG_I(RRC,"Dumping NR_RRCReconfiguration message (%jd bytes)\n",(enc_rval.encoded+7)>>3); - for (int i=0; i<(enc_rval.encoded+7)>>3; i++) { - printf("%02x",((uint8_t *)buffer)[i]); - } - printf("\n"); - fd = fopen("reconfig.raw","w"); - if (fd != NULL) { - fwrite((void *)buffer,1,(size_t)((enc_rval.encoded+7)>>3),fd); - fclose(fd); - } - } - - enc_rval = uper_encode_to_buffer(&asn_DEF_NR_RadioBearerConfig, NULL, (void *)rbconfig, buffer, 1024); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_RB_Config = calloc(1,sizeof(OCTET_STRING_t)); - - OCTET_STRING_fromBuf(cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_RB_Config, - (const char *)buffer, - (enc_rval.encoded+7)>>3); - - - - if (get_softmodem_params()->phy_test==1 || get_softmodem_params()->do_ra > 0) { - - LOG_I(RRC,"Dumping scg_RB_Config message (%jd bytes)\n",(enc_rval.encoded+7)>>3); - for (int i=0; i<(enc_rval.encoded+7)>>3; i++) { - printf("%02x",((uint8_t *)buffer)[i]); - } - - printf("\n"); - fd = fopen("rbconfig.raw","w"); - if (fd != NULL) { - fwrite((void *)buffer,1,(size_t)((enc_rval.encoded+7)>>3),fd); - fclose(fd); - } - } - - return cg_Config; -} - -#endif diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 477be84800..e6e50ffbf1 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -231,7 +231,6 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_ .plmn = rrc->configuration.plmn[0], .nr_cellid = rrc->nr_cellid, // TODO target cell ID .servCellId = 0, // TODO: correct value? - .ReconfigComplOutcome = RRCreconf_success, .transm_action_ind = &transmission_action_indicator, }; deliver_ue_ctxt_modification_data_t data = {.rrc = rrc, diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index e41875027e..120a400bbf 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -60,8 +60,9 @@ #include "openair2/F1AP/f1ap_ids.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" -#include "openair2/RRC/NR/rrc_gNB_GTPV1U.h" #include "openair3/SECU/key_nas_deriver.h" +#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" +#include "rrc_gNB_du.h" #include "rlc.h" #include "s1ap_messages_types.h" #include "tree.h" @@ -70,115 +71,87 @@ #include "x2ap_messages_types.h" #include "xer_decoder.h" #include "xer_encoder.h" +#include "f1ap_common.h" -void rrc_parse_ue_capabilities(gNB_RRC_INST *rrc, NR_UE_CapabilityRAT_ContainerList_t *UE_CapabilityRAT_ContainerList, x2ap_ENDC_sgnb_addition_req_t *m, NR_CG_ConfigInfo_IEs_t *cg_config_info) +// In case of phy-test and do-ra mode, read UE capabilities directly from file +// and put it into a CG-ConfigInfo field +static int cg_config_info_from_ue_cap_file(uint32_t maxlen, uint8_t buf[maxlen]) { - OCTET_STRING_t *ueCapabilityRAT_Container_nr=NULL; - OCTET_STRING_t *ueCapabilityRAT_Container_MRDC=NULL; - asn_dec_rval_t dec_rval; - int list_size=0; + NR_CG_ConfigInfo_t *cgci = calloc_or_fail(1, sizeof(*cgci)); + cgci->criticalExtensions.present = NR_CG_ConfigInfo__criticalExtensions_PR_c1; + cgci->criticalExtensions.choice.c1 = calloc_or_fail(1, sizeof(*cgci->criticalExtensions.choice.c1)); + cgci->criticalExtensions.choice.c1->present = NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo; + NR_CG_ConfigInfo_IEs_t *cgci_ies = calloc_or_fail(1, sizeof(*cgci_ies)); + cgci->criticalExtensions.choice.c1->choice.cg_ConfigInfo = cgci_ies; - AssertFatal(UE_CapabilityRAT_ContainerList!=NULL,"UE_CapabilityRAT_ContainerList is null\n"); - AssertFatal((list_size=UE_CapabilityRAT_ContainerList->list.count) >= 2, "UE_CapabilityRAT_ContainerList->list.size %d < 2\n",UE_CapabilityRAT_ContainerList->list.count); + if (uecap_file != NULL) { + LOG_I(NR_RRC, "creating CG-ConfigInfo from UE capability file %s\n", uecap_file); - for (int i=0; ilist.array[i]->rat_Type == NR_RAT_Type_nr) ueCapabilityRAT_Container_nr = &UE_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container; - else if (UE_CapabilityRAT_ContainerList->list.array[i]->rat_Type == NR_RAT_Type_eutra_nr) ueCapabilityRAT_Container_MRDC = &UE_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container; - } - - // decode and store capabilities - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_allocate_new_ue_context(rrc); - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - - if (ueCapabilityRAT_Container_nr != NULL) { - dec_rval = uper_decode(NULL, &asn_DEF_NR_UE_NR_Capability, (void **)&UE->UE_Capability_nr, ueCapabilityRAT_Container_nr->buf, ueCapabilityRAT_Container_nr->size, 0, 0); - - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - LOG_E(RRC, "Failed to decode UE NR capabilities (%zu bytes) container size %lu\n", dec_rval.consumed,ueCapabilityRAT_Container_nr->size); - ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr); - UE->UE_Capability_nr = 0; - AssertFatal(1==0,"exiting\n"); + FILE *f = fopen(uecap_file, "r"); + if (!f) { + LOG_E(NR_RRC, "cannot open file %s, cannot read UE capabilities\n", uecap_file); + return 0; } - } - - if (ueCapabilityRAT_Container_MRDC != NULL) { - dec_rval = uper_decode(NULL, &asn_DEF_NR_UE_MRDC_Capability, (void **)&UE->UE_Capability_MRDC, ueCapabilityRAT_Container_MRDC->buf, ueCapabilityRAT_Container_MRDC->size, 0, 0); - - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - LOG_E(RRC, "Failed to decode UE MRDC capabilities (%zu bytes)\n", dec_rval.consumed); - ASN_STRUCT_FREE(asn_DEF_NR_UE_MRDC_Capability, UE->UE_Capability_MRDC); - UE->UE_Capability_MRDC = 0; - AssertFatal(1==0,"exiting\n"); + char UE_NR_Capability_xer[65536]; + size_t size = fread(UE_NR_Capability_xer, 1, sizeof UE_NR_Capability_xer, f); + fclose(f); + if (size == 0 || size == sizeof UE_NR_Capability_xer) { + LOG_E(NR_RRC, "UE Capabilities XER file %s could not be read (read %ld bytes)\n", uecap_file, size); + return 0; } + NR_UE_NR_Capability_t *cap = calloc_or_fail(1, sizeof(*cap)); + asn_dec_rval_t dec_rval = xer_decode(0, &asn_DEF_NR_UE_NR_Capability, (void *)&cap, UE_NR_Capability_xer, size); + DevAssert(dec_rval.code == RC_OK); + //xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, cap); + + OCTET_STRING_t *os_cap = calloc_or_fail(1, sizeof(*os_cap)); + os_cap->size = uper_encode_to_new_buffer(&asn_DEF_NR_UE_NR_Capability, NULL, cap, (void **)&os_cap->buf); + cgci_ies->ue_CapabilityInfo = os_cap; } - // dump ue_capabilities + //xer_fprint(stdout, &asn_DEF_NR_CG_ConfigInfo, cgci); + asn_enc_rval_t rval = uper_encode_to_buffer(&asn_DEF_NR_CG_ConfigInfo, NULL, cgci, buf, maxlen); + DevAssert(rval.encoded > 0); + return (rval.encoded + 7) >> 3; +} - if ( LOG_DEBUGFLAG(DEBUG_ASN1) && ueCapabilityRAT_Container_nr != NULL ) { - xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr); - } - - if ( LOG_DEBUGFLAG(DEBUG_ASN1) && ueCapabilityRAT_Container_MRDC != NULL ) { - xer_fprint(stdout, &asn_DEF_NR_UE_MRDC_Capability, UE->UE_Capability_MRDC); - } - LOG_A(NR_RRC, "Successfully decoded UE NR capabilities (NR and MRDC)\n"); - - AssertFatal(NODE_IS_MONOLITHIC(rrc->node_type), "phy_test and do_ra only work in monolithic\n"); - LOG_I(NR_RRC,"Adding new NSA user (%p)\n",ue_context_p); - rrc_add_nsa_user(rrc,ue_context_p, m); +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, rrc_gNB_ue_context_t *ue_context_p, 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__); - // generate nr-Config-r15 containers for LTE RRC : inside message for X2 EN-DC (CG-Config Message from 38.331) - const nr_mac_config_t *configuration = &RC.nrmac[0]->radio_config; - MessageDef *msg; - msg = itti_alloc_new_message(TASK_RRC_ENB, 0, X2AP_ENDC_SGNB_ADDITION_REQ_ACK); - gtpv1u_enb_create_tunnel_req_t create_tunnel_req; - gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp; - protocol_ctxt_t ctxt={0}; - nr_pdcp_entity_security_keys_and_algos_t security_parameters = {0}; - int i; + + /* 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; - // In case of phy-test and do-ra mode, read UE capabilities directly from file - if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) { - NR_UE_NR_Capability_t* UE_Capability_nr = NULL; - char UE_NR_Capability_xer[65536]; - FILE *f = NULL; - if (uecap_file) - f = fopen(uecap_file, "r"); - if (f) { - size_t size = fread(UE_NR_Capability_xer, 1, sizeof UE_NR_Capability_xer, f); - if (size == 0 || size == sizeof UE_NR_Capability_xer) - LOG_E(NR_RRC,"UE Capabilities XER file %s is too large (%ld)\n", uecap_file, size); - else { - UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t)); - asn_dec_rval_t dec_rval = xer_decode(0, &asn_DEF_NR_UE_NR_Capability, (void *)&UE_Capability_nr, UE_NR_Capability_xer, size); - assert(dec_rval.code == RC_OK); - xer_fprint(stdout,&asn_DEF_NR_UE_NR_Capability,(void *)UE_Capability_nr); - } - fclose(f); - } - else - LOG_E(NR_RRC,"Could not open UE Capabilities input file. Not handling OAI UE Capabilities.\n"); - UE->UE_Capability_nr = UE_Capability_nr; - } + nr_pdcp_entity_security_keys_and_algos_t security_parameters = {0}; - // NR RRCReconfiguration + uint8_t tmp[1024]; + uint8_t *cgci_buf = NULL; + uint32_t cgci_len = 0; if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) { + DevAssert(m == NULL); UE->rb_config = get_default_rbconfig(10 /* EPS bearer ID */, 1 /* drb ID */, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master); + cgci_len = cg_config_info_from_ue_cap_file(sizeof tmp, tmp); + DevAssert(cgci_len > 0); + cgci_buf = tmp; } else { + DevAssert(m != NULL); + cgci_buf = m->rrc_buffer; + cgci_len = m->rrc_buffer_size; + /* TODO: handle more than one bearer */ - if (m == NULL) { - LOG_E(RRC, "fatal: m==NULL\n"); - exit(1); - } if (m->nb_e_rabs_tobeadded != 1) { LOG_E(RRC, "fatal: m->nb_e_rabs_tobeadded = %d, should be 1\n", m->nb_e_rabs_tobeadded); exit(1); @@ -196,7 +169,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a */ /* preset nea0 as fallback */ UE->ciphering_algorithm = 0; - for (i = 0; i < rrc->security.ciphering_algorithms_count; i++) { + for (int i = 0; i < rrc->security.ciphering_algorithms_count; i++) { int nea_mask[4] = { 0, 0x8000, /* nea1 */ @@ -254,27 +227,12 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a UE->rb_config = get_default_rbconfig(m->e_rabs_tobeadded[0].e_rab_id, m->e_rabs_tobeadded[0].drb_ID, cipher_algo, NR_SecurityConfig__keyToUse_secondary); } - NR_ServingCellConfig_t *scc = RC.nrmac[0]->common_channels[0].pre_ServingCellConfig; - // The MAC has the ServingCellConfigCommon; the below code is incorrect: the - // CU should send a UE Context Setup Request to request the creating of the - // MAC Context - NR_ServingCellConfigCommon_t *sccc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon; - NR_CellGroupConfig_t *secondaryCellGroup = - get_default_secondaryCellGroup(sccc, scc, UE->UE_Capability_nr, 1, 1, configuration, ue_context_p->ue_context.rrc_ue_id); - AssertFatal(secondaryCellGroup != NULL, "out of memory\n"); - - NR_RRCReconfiguration_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_t)); - reconfig->rrc_TransactionIdentifier = 0; - reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; - reconfig->criticalExtensions.choice.rrcReconfiguration = get_default_reconfig(secondaryCellGroup); - UE->rnti = secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity; - - NR_CG_Config_t *CG_Config = generate_CG_Config(reconfig, UE->rb_config); - if(m!=NULL) { - uint8_t inde_list[m->nb_e_rabs_tobeadded]; - memset(inde_list, 0, m->nb_e_rabs_tobeadded*sizeof(uint8_t)); + UE->x2_target_assoc = m->target_assoc_id; + UE->MeNB_ue_x2_id = m->ue_x2_id; + gtpv1u_enb_create_tunnel_req_t create_tunnel_req = {0}; + gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp = {0}; if (m->nb_e_rabs_tobeadded>0) { for (int i=0; inb_e_rabs_tobeadded; i++) { // Add the new E-RABs at the corresponding rrc ue context of the gNB @@ -286,7 +244,6 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a create_tunnel_req.eps_bearer_id[i] = UE->e_rab[i].param.e_rab_id; create_tunnel_req.sgw_S1u_teid[i] = UE->e_rab[i].param.gtp_teid; memcpy(&create_tunnel_req.sgw_addr[i], &UE->e_rab[i].param.sgw_addr, sizeof(transport_layer_addr_t)); - inde_list[i] = i; LOG_I(RRC,"S1-U tunnel: index %d target sgw ip %d.%d.%d.%d length %d gtp teid %u\n", i, create_tunnel_req.sgw_addr[i].buffer[0], @@ -300,146 +257,217 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a create_tunnel_req.rnti = ue_context_p->ue_context.rrc_ue_id; create_tunnel_req.num_tunnels = m->nb_e_rabs_tobeadded; RB_INSERT(rrc_nr_ue_tree_s, &RC.nrrrc[rrc->module_id]->rrc_ue_head, ue_context_p); - memset(&create_tunnel_resp, 0, sizeof(create_tunnel_resp)); if (!IS_SOFTMODEM_NOS1) { - LOG_D(RRC, "Calling gtpv1u_create_s1u_tunnel()\n"); gtpv1u_create_s1u_tunnel(rrc->module_id, &create_tunnel_req, &create_tunnel_resp, nr_pdcp_data_req_drb); - rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ue_context_p->ue_context, &create_tunnel_resp, &inde_list[0]); + DevAssert(create_tunnel_resp.num_tunnels == 1); + UE->nsa_gtp_teid[0] = create_tunnel_resp.enb_S1u_teid[0]; + UE->nsa_gtp_addrs[0] = create_tunnel_resp.enb_addr; + UE->nsa_gtp_ebi[0] = create_tunnel_resp.eps_bearer_id[0]; } - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).nb_e_rabs_admitted_tobeadded = m->nb_e_rabs_tobeadded; - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).target_assoc_id = m->target_assoc_id; - - for (int i = 0; i < UE->nb_of_e_rabs; i++) { - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].e_rab_id = UE->e_rab[i].param.e_rab_id; - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gtp_teid = create_tunnel_resp.enb_S1u_teid[i]; - memcpy(&X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr, &create_tunnel_resp.enb_addr, sizeof(transport_layer_addr_t)); - //The length field in the X2AP targetting structure is expected in bits but the create_tunnel_resp returns the address length in bytes - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.length = create_tunnel_resp.enb_addr.length*8; - LOG_I(RRC,"S1-U create_tunnel_resp tunnel: index %d target gNB ip %d.%d.%d.%d length %d gtp teid %u\n", - i, - create_tunnel_resp.enb_addr.buffer[0], - create_tunnel_resp.enb_addr.buffer[1], - create_tunnel_resp.enb_addr.buffer[2], - create_tunnel_resp.enb_addr.buffer[3], - create_tunnel_resp.enb_addr.length, - create_tunnel_resp.enb_S1u_teid[i]); - LOG_I(RRC,"X2AP sGNB Addition Request: index %d target gNB ip %d.%d.%d.%d length %d gtp teid %u\n", - i, - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[0], - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[1], - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[2], - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[3], - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.length, - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gtp_teid); - } - } else - LOG_W(RRC, "No E-RAB to be added received from SgNB Addition Request message \n"); - - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).MeNB_ue_x2_id = m->ue_x2_id; - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).SgNB_ue_x2_id = secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity; - //X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = CG_Config_size; //Need to verify correct value for the buffer_size - // Send to X2 entity to transport to MeNB - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CG_Config, - NULL, - (void *)CG_Config, - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer, - sizeof(X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer)); - X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = (enc_rval.encoded+7)>>3; - itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(0), msg); //Check right id instead of hardcoding + } } - // below we configure the stack. In SA, we fully adopted F1, meaning that - // layers use different IDs (MAC/RLC use RNTI as DU UE ID, above use NGAP ID - // as CU UE ID. - uint32_t du_ue_id = ue_context_p->ue_context.rnti; - uint32_t rrc_ue_id = ue_context_p->ue_context.rrc_ue_id; - f1_ue_data_t du_ue_data = {.secondary_ue = rrc_ue_id}; - bool success = du_add_f1_ue_data(du_ue_id, &du_ue_data); - DevAssert(success); - f1_ue_data_t cu_ue_data = {.secondary_ue = du_ue_id}; - success = cu_add_f1_ue_data(rrc_ue_id, &cu_ue_data); - DevAssert(success); - LOG_I(RRC, "Assign CU UE ID %d and DU UE ID %d to UE RNTI %04x\n", rrc_ue_id, du_ue_id, ue_context_p->ue_context.rnti); - - // configure MAC and RLC - bool ret = false; - if (get_softmodem_params()->phy_test) { - // phytest mode: we don't set up RA, etc - ret = nr_mac_add_test_ue(RC.nrmac[rrc->module_id], du_ue_id, secondaryCellGroup); - } else { - DevAssert(secondaryCellGroup->spCellConfig - && secondaryCellGroup->spCellConfig->reconfigurationWithSync - && secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated - && secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra); - NR_SCHED_LOCK(&RC.nrmac[rrc->module_id]->sched_lock); - ret = nr_mac_prepare_ra_ue(RC.nrmac[rrc->module_id], du_ue_id, secondaryCellGroup); - NR_SCHED_UNLOCK(&RC.nrmac[rrc->module_id]->sched_lock); - } - AssertFatal(ret, "cannot add NSA UE in MAC, aborting\n"); - - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, rrc_ue_id, 0, 0, rrc->module_id); - LOG_W(RRC, - "Calling RRC PDCP/RLC ASN1 request functions for protocol context %p with module_id %d, rnti %lx, frame %d, subframe %d eNB_index %d \n", - &ctxt, - ctxt.module_id, - ctxt.rntiMaybeUEid, - ctxt.frame, - ctxt.subframe, - ctxt.eNB_index); - - nr_pdcp_add_drbs(ctxt.enb_flag, - rrc_ue_id, - ue_context_p->ue_context.rb_config->drb_ToAddModList, + DevAssert(UE->rb_config != NULL); + nr_pdcp_add_drbs(GNB_FLAG_YES, + UE->rrc_ue_id, + UE->rb_config->drb_ToAddModList, &security_parameters); - ctxt.rntiMaybeUEid = du_ue_id; - // assume only a single bearer - const NR_DRB_ToAddModList_t *drb_list = ue_context_p->ue_context.rb_config->drb_ToAddModList; - DevAssert(drb_list->list.count == 1); - const NR_DRB_ToAddMod_t *drb = drb_list->list.array[0]; - const struct NR_CellGroupConfig__rlc_BearerToAddModList *bearer_list = secondaryCellGroup->rlc_BearerToAddModList; - const NR_RLC_BearerConfig_t *bearer = bearer_list->list.array[0]; - DevAssert(bearer_list->list.count == 1); - DevAssert(drb->drb_Identity == bearer->servedRadioBearer->choice.drb_Identity); - nr_rlc_add_drb(ctxt.rntiMaybeUEid, drb->drb_Identity, bearer); - - LOG_D(RRC, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %lx\n", __FUNCTION__, __LINE__, ctxt.rntiMaybeUEid); + cu_to_du_rrc_information_t cu2du = { + .cG_ConfigInfo = cgci_buf, + .cG_ConfigInfo_length = cgci_len, + }; + /* 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 = 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 */ + .plmn.mcc = rrc->configuration.plmn[0].mcc, + .plmn.mnc = rrc->configuration.plmn[0].mnc, + .plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length, + .nr_cellid = rrc->nr_cellid, + .servCellId = 0, + .drbs_to_be_setup_length = 1, + .drbs_to_be_setup = &drbs, + .cu_to_du_rrc_information = &cu2du, + }; + f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); + rrc->mac_rrc.ue_context_setup_request(ue_data.du_assoc_id, &req); } -void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti) { - protocol_ctxt_t ctxt; - rrc_gNB_ue_context_t *ue_context; - int e_rab; +static NR_RRCReconfiguration_IEs_t *get_default_reconfig(const NR_CellGroupConfig_t *secondaryCellGroup) +{ + NR_RRCReconfiguration_IEs_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t)); + AssertFatal(reconfig != NULL, "out of memory\n"); + AssertFatal(secondaryCellGroup != NULL, "secondaryCellGroup is null\n"); + reconfig->radioBearerConfig = NULL; - LOG_D(RRC, "calling rrc_remove_nsa_user rnti %x\n", rnti); - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, rnti, 0, 0, rrc->module_id); + char scg_buffer[1024]; + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, (void *)secondaryCellGroup, scg_buffer, 1024); + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded); + reconfig->secondaryCellGroup = calloc(1, sizeof(*reconfig->secondaryCellGroup)); + OCTET_STRING_fromBuf(reconfig->secondaryCellGroup, (const char *)scg_buffer, (enc_rval.encoded + 7) >> 3); + reconfig->measConfig = NULL; + reconfig->lateNonCriticalExtension = NULL; + reconfig->nonCriticalExtension = NULL; + return reconfig; +} - ue_context = rrc_gNB_get_ue_context_by_rnti_any_du(rrc, rnti); - if (ue_context == NULL) { - LOG_W(RRC, "rrc_remove_nsa_user: rnti %x not found\n", rnti); +static NR_CG_Config_t *generate_CG_Config(const NR_RRCReconfiguration_t *reconfig, const NR_RadioBearerConfig_t *rbconfig) +{ + NR_CG_Config_t *cg_Config = calloc_or_fail(1, sizeof(*cg_Config)); + cg_Config->criticalExtensions.present = NR_CG_Config__criticalExtensions_PR_c1; + cg_Config->criticalExtensions.choice.c1 = calloc_or_fail(1, sizeof(*cg_Config->criticalExtensions.choice.c1)); + cg_Config->criticalExtensions.choice.c1->present = NR_CG_Config__criticalExtensions__c1_PR_cg_Config; + NR_CG_Config_IEs_t *cgc_ie = calloc_or_fail(1, sizeof(*cgc_ie)); + cg_Config->criticalExtensions.choice.c1->choice.cg_Config = cgc_ie; + cgc_ie->scg_CellGroupConfig = calloc_or_fail(1, sizeof(*cgc_ie->scg_CellGroupConfig)); + cgc_ie->scg_CellGroupConfig->size = + uper_encode_to_new_buffer(&asn_DEF_NR_RRCReconfiguration, NULL, reconfig, (void **)&cgc_ie->scg_CellGroupConfig->buf); + AssertFatal(cgc_ie->scg_CellGroupConfig->size > 0, + "ASN1 message encoding of RRCReconfiguration failed (%ld)!\n", + cgc_ie->scg_CellGroupConfig->size); + + cgc_ie->scg_RB_Config = calloc_or_fail(1, sizeof(*cgc_ie->scg_RB_Config)); + cgc_ie->scg_RB_Config->size = + uper_encode_to_new_buffer(&asn_DEF_NR_RadioBearerConfig, NULL, rbconfig, (void **)&cgc_ie->scg_RB_Config->buf); + AssertFatal(cgc_ie->scg_RB_Config->size > 0, "ASN1 message encoding failed (%ld)!\n", cgc_ie->scg_RB_Config->size); + + if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra > 0) { + // This is for phytest only, emulate first X2 message if uecap.raw file is present + LOG_I(RRC, "Dumping NR_RRCReconfiguration message (%jd bytes) to reconfig.raw\n", cgc_ie->scg_CellGroupConfig->size); + FILE *fd = fopen("reconfig.raw", "w"); + AssertFatal(fd != NULL, "could not open reconig.raw for writing: %d, %s\n", errno, strerror(errno)); + fwrite(cgc_ie->scg_CellGroupConfig->buf, cgc_ie->scg_CellGroupConfig->size, 1, fd); + fclose(fd); + + LOG_I(RRC, "Dumping scg_RB_Config message (%jd bytes) to reconfig.raw\n", cgc_ie->scg_RB_Config->size); + fd = fopen("rbconfig.raw", "w"); + AssertFatal(fd != NULL, "could not open rbconig.raw for writing: %d, %s\n", errno, strerror(errno)); + fwrite(cgc_ie->scg_RB_Config->buf, cgc_ie->scg_RB_Config->size, 1, fd); + fclose(fd); + } + + return cg_Config; +} + +void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp) +{ + DevAssert(resp->crnti != NULL); + /* we did not fill any DU-related ID info in rrc_add_nsa_user() */ + UE->rnti = *resp->crnti; + DevAssert(cu_exists_f1_ue_data(UE->rrc_ue_id)); + f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); + ue_data.secondary_ue = resp->gNB_DU_ue_id; + 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; + reconfig->criticalExtensions.choice.rrcReconfiguration = get_default_reconfig(UE->masterCellGroup); + + NR_CG_Config_t *CG_Config = generate_CG_Config(reconfig, UE->rb_config); + + if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) { + /* we are done, no X2 answer necessary */ + ASN_STRUCT_FREE(asn_DEF_NR_CG_Config, CG_Config); return; } - nr_pdcp_remove_UE(ue_context->ue_context.rrc_ue_id); - rrc_rlc_remove_ue(&ctxt); + MessageDef *msg = itti_alloc_new_message(TASK_RRC_ENB, 0, X2AP_ENDC_SGNB_ADDITION_REQ_ACK); + x2ap_ENDC_sgnb_addition_req_ACK_t *ack = &X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg); - // lock the scheduler before removing the UE. Note: mac_remove_nr_ue() checks - // that the scheduler is actually locked! - NR_SCHED_LOCK(&RC.nrmac[rrc->module_id]->sched_lock); - mac_remove_nr_ue(RC.nrmac[rrc->module_id], rnti); - NR_SCHED_UNLOCK(&RC.nrmac[rrc->module_id]->sched_lock); - gtpv1u_enb_delete_tunnel_req_t tmp={0}; - tmp.rnti=rnti; - tmp.from_gnb=1; - LOG_D(RRC, "ue_context->ue_context.nb_of_e_rabs %d will be deleted for rnti %x\n", ue_context->ue_context.nb_of_e_rabs, rnti); - for (e_rab = 0; e_rab < ue_context->ue_context.nb_of_e_rabs; e_rab++) { - tmp.eps_bearer_id[tmp.num_erab++]= ue_context->ue_context.nsa_gtp_ebi[e_rab]; - // erase data - ue_context->ue_context.nsa_gtp_teid[e_rab] = 0; - memset(&ue_context->ue_context.nsa_gtp_addrs[e_rab], 0, sizeof(ue_context->ue_context.nsa_gtp_addrs[e_rab])); - ue_context->ue_context.nsa_gtp_ebi[e_rab] = 0; + ack->nb_e_rabs_admitted_tobeadded = UE->nb_of_e_rabs; + DevAssert(UE->x2_target_assoc > 0); + ack->target_assoc_id = UE->x2_target_assoc; + + for (int i = 0; i < UE->nb_of_e_rabs; i++) { + ack->e_rabs_admitted_tobeadded[i].e_rab_id = UE->e_rab[i].param.e_rab_id; + ack->e_rabs_admitted_tobeadded[i].gtp_teid = UE->nsa_gtp_teid[0]; + memcpy(&ack->e_rabs_admitted_tobeadded[i].gnb_addr, &UE->nsa_gtp_addrs[0], sizeof(transport_layer_addr_t)); + ack->e_rabs_admitted_tobeadded[i].gnb_addr.length = 32; // bits, IPv4 only } - gtpv1u_delete_all_s1u_tunnel(rrc->module_id, rnti); - /* remove context */ - rrc_gNB_remove_ue_context(rrc, ue_context); + + ack->MeNB_ue_x2_id = UE->MeNB_ue_x2_id; + ack->SgNB_ue_x2_id = UE->rrc_ue_id; + + // Send to X2 entity to transport to MeNB + asn_enc_rval_t enc_rval = + uper_encode_to_buffer(&asn_DEF_NR_CG_Config, NULL, (void *)CG_Config, ack->rrc_buffer, sizeof(ack->rrc_buffer)); + ack->rrc_buffer_size = (enc_rval.encoded + 7) >> 3; + itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(0), msg); + ASN_STRUCT_FREE(asn_DEF_NR_CG_Config, CG_Config); +} + +void rrc_remove_nsa_user_context(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context) +{ + 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); +} + +void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context) +{ + gNB_RRC_UE_t *UE = &ue_context->ue_context; + f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); + f1ap_ue_context_release_cmd_t cmd = { + .gNB_CU_ue_id = UE->rrc_ue_id, + .gNB_DU_ue_id = ue_data.secondary_ue, + .cause = F1AP_CAUSE_RADIO_NETWORK, + .cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release + }; + rrc->mac_rrc.ue_context_release_command(ue_data.du_assoc_id, &cmd); + rrc_remove_nsa_user_context(rrc, ue_context); } diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c deleted file mode 100644 index 57e9b28dc6..0000000000 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file rrc_gNB_reconfig.c - * \brief rrc gNB RRCreconfiguration support routines - * \author Raymond Knopp - * \date 2019 - * \version 1.0 - * \company Eurecom - * \email: raymond.knopp@eurecom.fr - */ -#ifndef RRC_GNB_NSA_C -#define RRC_GNB_NSA_C - -#include - -#include "OCTET_STRING.h" -#include "RRC/NR/nr_rrc_proto.h" -#include "asn_codecs.h" -#include "assertions.h" -#include "constr_TYPE.h" -#include "oai_asn1.h" -#include "uper_encoder.h" - -NR_RRCReconfiguration_IEs_t *get_default_reconfig(const NR_CellGroupConfig_t *secondaryCellGroup) -{ - NR_RRCReconfiguration_IEs_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t)); - AssertFatal(reconfig != NULL, "out of memory\n"); - AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n"); - // radioBearerConfig - reconfig->radioBearerConfig=NULL; - - char scg_buffer[1024]; - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, (void *)secondaryCellGroup, scg_buffer, 1024); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded); - reconfig->secondaryCellGroup = calloc(1,sizeof(*reconfig->secondaryCellGroup)); - OCTET_STRING_fromBuf(reconfig->secondaryCellGroup, - (const char *)scg_buffer, - (enc_rval.encoded+7)>>3); - // measConfig - reconfig->measConfig=NULL; - // lateNonCriticalExtension - reconfig->lateNonCriticalExtension = NULL; - // nonCriticalExtension - reconfig->nonCriticalExtension = NULL; - return reconfig; -} -#endif diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index f7aa232c71..b36c2d676d 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1138,8 +1138,7 @@ static void rrc_ue_generate_RRCSetupComplete(const NR_UE_RRC_INST_t *rrc, const nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL); } -static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc, - const NR_RRCSetup_t *rrcSetup) +static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc, const NR_RRCSetup_t *rrcSetup) { // if the RRCSetup is received in response to an RRCReestablishmentRequest // or RRCResumeRequest or RRCResumeRequest1 diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index 1fe8e925a7..44b8fa2cb0 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -107,17 +107,10 @@ void sdap_data_ind(rb_id_t pdcp_entity, size); } -struct thread_args { - nr_sdap_entity_t *entity; - bool is_gnb; -}; static void *sdap_tun_read_thread(void *arg) { DevAssert(arg != NULL); - struct thread_args *ta = arg; - nr_sdap_entity_t *entity = ta->entity; - bool is_gnb = ta->is_gnb; - free(ta); + nr_sdap_entity_t *entity = arg; char rx_buf[NL_MAX_PAYLOAD]; int len; @@ -134,9 +127,9 @@ static void *sdap_tun_read_thread(void *arg) LOG_D(SDAP, "read data of size %d\n", len); - protocol_ctxt_t ctxt = {.enb_flag = is_gnb, .rntiMaybeUEid = entity->ue_id}; + protocol_ctxt_t ctxt = {.enb_flag = entity->is_gnb, .rntiMaybeUEid = entity->ue_id}; - bool dc = is_gnb ? false : SDAP_HDR_UL_DATA_PDU; + bool dc = entity->is_gnb ? false : SDAP_HDR_UL_DATA_PDU; DevAssert(entity != NULL); entity->tx_entity(entity, @@ -161,30 +154,25 @@ void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id) { nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, get_softmodem_params()->default_pdu_session_id); DevAssert(entity != NULL); + DevAssert(entity->is_gnb); char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; char ifname[IFNAMSIZ]; tun_generate_ifname(ifname, ifprefix, ue_id - 1); entity->pdusession_sock = tun_alloc(ifname); tun_config(ifname, "10.0.1.1", NULL); - struct thread_args *ta = calloc_or_fail(1, sizeof(*ta)); - ta->entity = entity; - ta->is_gnb = true; - - threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW); + threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW); } void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock) { nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id); DevAssert(entity != NULL); + DevAssert(!entity->is_gnb); entity->pdusession_sock = sock; entity->stop_thread = false; char thread_name[64]; snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id); - struct thread_args *ta = calloc_or_fail(1, sizeof(*ta)); - ta->entity = entity; - ta->is_gnb = false; - threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, thread_name, -1, OAI_PRIORITY_RT_LOW); + threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, thread_name, -1, OAI_PRIORITY_RT_LOW); } @@ -201,7 +189,7 @@ void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_sess start_sdap_tun_ue(ue_id, pdu_session_id, sock); // interface name suffix is ue_id+1 } -void remove_ue_ip_if(nr_sdap_entity_t *entity) +void remove_ip_if(nr_sdap_entity_t *entity) { DevAssert(entity != NULL); // Stop the read thread @@ -211,6 +199,11 @@ void remove_ue_ip_if(nr_sdap_entity_t *entity) // Bring down the IP interface int default_pdu = get_softmodem_params()->default_pdu_session_id; char ifname[IFNAMSIZ]; - tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1); + if (entity->is_gnb) { + char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; + tun_generate_ifname(ifname, ifprefix, entity->ue_id - 1); + } else { + tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1); + } tun_destroy(ifname, entity->pdusession_sock); } diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index aa6ee95b47..d93a508c33 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -502,6 +502,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, sdap_entity->ue_id = ue_id; sdap_entity->pdusession_id = pdusession_id; + sdap_entity->is_gnb = is_gnb; sdap_entity->tx_entity = nr_sdap_tx_entity; sdap_entity->rx_entity = nr_sdap_rx_entity; @@ -587,6 +588,8 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) { sdap_info.sdap_entity_llist = sdap_info.sdap_entity_llist->next_entity; + if (entityPtr->pdusession_sock != -1) + remove_ip_if(entityPtr); free(entityPtr); LOG_D(SDAP, "Successfully deleted Entity.\n"); ret = true; @@ -600,8 +603,8 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) { entityPrev->next_entity = entityPtr->next_entity; - if (entityPrev->pdusession_sock != -1) { - remove_ue_ip_if(entityPrev); + if (entityPtr->pdusession_sock != -1) { + remove_ip_if(entityPtr); } free(entityPtr); LOG_D(SDAP, "Successfully deleted Entity.\n"); @@ -627,6 +630,8 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id) /* Handle scenario where ue_id matches the head of the list */ while (entityPtr != NULL && entityPtr->ue_id == ue_id && upperBound < MAX_DRBS_PER_UE) { sdap_info.sdap_entity_llist = entityPtr->next_entity; + if (entityPtr->pdusession_sock != -1) + remove_ip_if(entityPtr); free(entityPtr); entityPtr = sdap_info.sdap_entity_llist; ret = true; @@ -638,6 +643,8 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id) entityPtr = entityPtr->next_entity; } else { entityPrev->next_entity = entityPtr->next_entity; + if (entityPtr->pdusession_sock != -1) + remove_ip_if(entityPtr); free(entityPtr); entityPtr = entityPrev->next_entity; LOG_I(SDAP, "Successfully deleted SDAP entity for UE %ld\n", ue_id); diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index adfc48e663..3a42c6c076 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -80,6 +80,9 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s typedef struct nr_sdap_entity_s { ue_id_t ue_id; rb_id_t default_drb; + /// sdap_tun_read_thread needs to know if we are gNB/UE, so for noS1 mode, + /// store which one we are + bool is_gnb; int pdusession_id; int pdusession_sock; pthread_t pdusession_thread; @@ -218,5 +221,5 @@ bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config); void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, int pdusession_id, int drb_id); void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id); -void remove_ue_ip_if(nr_sdap_entity_t *entity); +void remove_ip_if(nr_sdap_entity_t *entity); #endif