diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 9b6528d7b0..501eb963c0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2809,6 +2809,34 @@ int nr_mac_enable_ue_rrc_processing_timer(gNB_MAC_INST *mac, NR_UE_info_t *UE, b return 0; } +void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti) +{ + NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); + + nr_rlc_remove_ue(rnti); + mac_remove_nr_ue(mac, rnti); + + // the CU might not know such UE, e.g., because we never sent a message to + // it, so there might not be a corresponding entry for such UE in the look up + // table. This can happen, e.g., on Msg.3 with C-RNTI, where we create a UE + // MAC context, decode the PDU, find the C-RNTI MAC CE, and then throw the + // newly created context away. See also in _nr_rx_sdu() and commit 93f59a3c6e56f + if (du_exists_f1_ue_data(rnti)) { + // unlock the scheduler temporarily to prevent possible deadlocks with + // du_remove_f1_ue_data() (and also while sending the message to RRC) + NR_SCHED_UNLOCK(&mac->sched_lock); + f1_ue_data_t ue_data = du_get_f1_ue_data(rnti); + f1ap_ue_context_release_complete_t complete = { + .gNB_CU_ue_id = ue_data.secondary_ue, + .gNB_DU_ue_id = rnti, + }; + mac->mac_rrc.ue_context_release_complete(&complete); + + du_remove_f1_ue_data(rnti); + NR_SCHED_LOCK(&mac->sched_lock); + } +} + void nr_mac_update_timers(module_id_t module_id, frame_t frame, sub_frame_t slot) @@ -2823,8 +2851,7 @@ void nr_mac_update_timers(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; if (nr_mac_check_release(sched_ctrl, UE->rnti)) { - nr_rlc_remove_ue(UE->rnti); - mac_remove_nr_ue(mac, UE->rnti); + nr_mac_release_ue(mac, UE->rnti); // go back to examine the next UE, which is at the position the // current UE was UE--; @@ -2963,7 +2990,7 @@ void prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE) void nr_mac_trigger_release_timer(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing) { // trigger 60ms - sched_ctrl->release_timer = 60 << subcarrier_spacing; + sched_ctrl->release_timer = 100 << subcarrier_spacing; } bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 9f96a0d106..e58d2c12ae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -443,6 +443,7 @@ void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid); void nr_mac_trigger_release_timer(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing); bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti); +void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti); void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing); void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl); 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 9eda0ceaf1..5157ff453f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -493,27 +493,24 @@ void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd) { /* mark UE as to be deleted after PUSCH failure */ gNB_MAC_INST *mac = RC.nrmac[0]; - pthread_mutex_lock(&mac->sched_lock); + NR_SCHED_LOCK(&mac->sched_lock); NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, cmd->gNB_DU_ue_id); + if (UE == NULL) { + LOG_E(MAC, "ERROR: unknown UE with RNTI %04x, ignoring UE Context Release Command\n", cmd->gNB_DU_ue_id); + NR_SCHED_UNLOCK(&mac->sched_lock); + return; + } + if (UE->UE_sched_ctrl.ul_failure || cmd->rrc_container_length == 0) { /* The UE is already not connected anymore or we have nothing to forward*/ - nr_rlc_remove_ue(cmd->gNB_DU_ue_id); - mac_remove_nr_ue(mac, cmd->gNB_DU_ue_id); + nr_mac_release_ue(mac, cmd->gNB_DU_ue_id); } else { /* UE is in sync: forward release message and mark to be deleted * after UL failure */ nr_rlc_srb_recv_sdu(cmd->gNB_DU_ue_id, cmd->srb_id, cmd->rrc_container, cmd->rrc_container_length); nr_mac_trigger_release_timer(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); } - pthread_mutex_unlock(&mac->sched_lock); - - f1ap_ue_context_release_complete_t complete = { - .gNB_CU_ue_id = cmd->gNB_CU_ue_id, - .gNB_DU_ue_id = cmd->gNB_DU_ue_id, - }; - mac->mac_rrc.ue_context_release_complete(&complete); - - du_remove_f1_ue_data(cmd->gNB_DU_ue_id); + NR_SCHED_UNLOCK(&mac->sched_lock); } void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6c3de095e5..25ca92cd90 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2503,10 +2503,6 @@ static void write_rrc_stats(const gNB_RRC_INST *rrc) { const gNB_RRC_UE_t *ue_ctxt = &ue_context_p->ue_context; f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_ctxt->rrc_ue_id); - /* currently, we support only one DU. If we support multiple, need to - * search for the DU corresponding to this UE here */ - const nr_rrc_du_container_t *du = rrc->du; - DevAssert(du != NULL); fprintf(f, "UE %d CU UE ID %d DU UE ID %d RNTI %04x random identity %016lx", @@ -2528,7 +2524,10 @@ static void write_rrc_stats(const gNB_RRC_INST *rrc) fprintf(f, " PDU session %d ID %d status %s\n", nb_pdu, pdu->param.pdusession_id, get_pdusession_status_text(pdu->status)); } - if (ue_ctxt->UE_Capability_nr) { + /* currently, we support only one DU. If we support multiple, need to + * search for the DU corresponding to this UE here */ + const nr_rrc_du_container_t *du = rrc->du; + if (du != NULL && ue_ctxt->UE_Capability_nr) { AssertFatal(du->setup_req->num_cells_available == 1, "only one cell supported at the moment\n"); const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; fprintf(f,