diff --git a/openair2/COMMON/f1ap_messages_def.h b/openair2/COMMON/f1ap_messages_def.h index 5db598409f..7b991e5918 100644 --- a/openair2/COMMON/f1ap_messages_def.h +++ b/openair2/COMMON/f1ap_messages_def.h @@ -39,6 +39,7 @@ MESSAGE_DEF(F1AP_UL_RRC_MESSAGE , MESSAGE_PRIORITY_MED, f1ap_ul_r //MESSAGE_DEF(F1AP_INITIAL_CONTEXT_SETUP_FAILURE, MESSAGE_PRIORITY_MED, f1ap_initial_context_setup_failure_t, f1ap_initial_context_setup_failure) MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_release_req_t, f1ap_ue_context_release_req) MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_CMD, MESSAGE_PRIORITY_MED, f1ap_ue_context_release_cmd_t, f1ap_ue_context_release_cmd) +MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_COMPLETE, MESSAGE_PRIORITY_MED, f1ap_ue_context_release_complete_t, f1ap_ue_context_release_complete) /* RRC -> F1AP messages */ MESSAGE_DEF(F1AP_DL_RRC_MESSAGE , MESSAGE_PRIORITY_MED, f1ap_dl_rrc_message_t , f1ap_dl_rrc_message ) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 541188cbd2..9bdf7f0330 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -41,14 +41,14 @@ #define F1AP_UL_RRC_MESSAGE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ul_rrc_message #define F1AP_UE_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_setup_req #define F1AP_UE_CONTEXT_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_setup_resp -#define F1AP_UE_CONTEXT_RELEASE_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_resp #define F1AP_UE_CONTEXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_req #define F1AP_UE_CONTEXT_MODIFICATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_resp #define F1AP_UE_CONTEXT_MODIFICATION_FAIL(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_fail #define F1AP_DL_RRC_MESSAGE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_dl_rrc_message #define F1AP_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_req -#define F1AP_UE_CONTEXT_RELEASE_CMD(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_req +#define F1AP_UE_CONTEXT_RELEASE_CMD(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_cmd +#define F1AP_UE_CONTEXT_RELEASE_COMPLETE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_complete #define F1AP_PAGING_IND(mSGpTR) (mSGpTR)->ittiMsg.f1ap_paging_ind diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index 8717382dfc..098f957194 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -165,6 +165,10 @@ void *F1AP_DU_task(void *arg) { &F1AP_UE_CONTEXT_RELEASE_REQ(msg)); break; + case F1AP_UE_CONTEXT_RELEASE_COMPLETE: + DU_send_UE_CONTEXT_RELEASE_COMPLETE(myInstance, &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg)); + break; + case TERMINATE_MESSAGE: LOG_W(F1AP, " *** Exiting F1AP thread\n"); itti_exit_task(); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 33bd6831d1..9545f8feb7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2785,6 +2785,16 @@ void nr_mac_update_timers(module_id_t module_id, NR_UEs_t *UE_info = &RC.nrmac[module_id]->UE_info; UE_iterator(UE_info->list, UE) { 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(RC.nrmac[module_id], UE->rnti); + // go back to examine the next UE, which is at the position the + // current UE was + UE--; + continue; + } + if (sched_ctrl->rrc_processing_timer > 0) { sched_ctrl->rrc_processing_timer--; if (sched_ctrl->rrc_processing_timer == 0) { @@ -2946,3 +2956,17 @@ void prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE) DevAssert(bearer->servedRadioBearer->choice.srb_Identity == 1); nr_rlc_add_srb(UE->rnti, DCCH, bearer); } + +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; +} + +bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti) +{ + if (sched_ctrl->release_timer == 0) + return false; + sched_ctrl->release_timer--; + return sched_ctrl->release_timer == 0; +} diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 80c1652b61..cf20ca5d1a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -671,8 +671,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, if (!get_softmodem_params()->phy_test && UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt >= pusch_failure_thres) { LOG_W(NR_MAC,"Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt); - UE->UE_sched_ctrl.ul_failure = 1; - nr_mac_gNB_rrc_ul_failure(gnb_mod_idP,CC_idP,frameP,slotP,rntiP); } } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index c2cbe8799d..a94a99d452 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -440,4 +440,7 @@ void send_initial_ul_rrc_message(gNB_MAC_INST *mac, int rnti, const uint8_t *sdu 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); + #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 dfa01a8454..2cf37946ea 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -149,7 +149,29 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd) { - AssertFatal(false, "not implemented\n"); + /* mark UE as to be deleted after PUSCH failure */ + gNB_MAC_INST *mac = RC.nrmac[0]; + pthread_mutex_lock(&mac->sched_lock); + NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, cmd->rnti); + if (UE->UE_sched_ctrl.ul_failure > 0 || cmd->rrc_container_length == 0) { + /* The UE is already not connected anymore or we have nothing to forward*/ + nr_rlc_remove_ue(cmd->rnti); + mac_remove_nr_ue(mac, cmd->rnti); + } else { + /* UE is in sync: forward release message and mark to be deleted + * after UL failure */ + nr_rlc_srb_recv_sdu(cmd->rnti, 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 = { + .rnti = cmd->rnti, + }; + mac->mac_rrc.ue_context_release_complete(&complete); + + if (cmd->rrc_container) + free(cmd->rrc_container); } int dl_rrc_message(module_id_t module_id, const f1ap_dl_rrc_message_t *dl_rrc) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index 694b0906a2..5db1596a97 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -62,7 +62,10 @@ static void ue_context_release_request_direct(const f1ap_ue_context_release_req_ static void ue_context_release_complete_direct(const f1ap_ue_context_release_complete_t *complete) { - AssertFatal(false, "not implemented\n"); + MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_COMPLETE); + f1ap_ue_context_release_complete_t *f1ap_msg = &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg); + *f1ap_msg = *complete; + itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } static void initial_ul_rrc_message_transfer_direct(module_id_t module_id, const f1ap_initial_ul_rrc_message_t *ul_rrc) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 2571754843..8df47be1e9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -592,6 +592,7 @@ typedef struct { int pusch_consecutive_dtx_cnt; int pucch_consecutive_dtx_cnt; int ul_failure; + int release_timer; struct CSI_Report CSI_report; bool SR; /// information about every HARQ process diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2bc3892c4d..b955c7147d 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2589,6 +2589,21 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance * messages (UE capability, to be specific) */ } +static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p) +{ + const int instance = 0; + f1ap_ue_context_release_complete_t *complete = &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg_p); + gNB_RRC_INST *rrc = RC.nrrrc[instance]; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, complete->rnti); + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + + nr_pdcp_remove_UE(UE->rnti); + newGtpuDeleteAllTunnels(instance, UE->rnti); + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance, UE->gNB_ue_ngap_id); + LOG_I(NR_RRC, "removed UE %04x \n", UE->rnti); + rrc_gNB_remove_ue_context(rrc, ue_context_p); +} + static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, instance_t instance) { f1ap_ue_context_setup_t *resp=&F1AP_UE_CONTEXT_SETUP_RESP(msg_p); @@ -3162,9 +3177,12 @@ void *rrc_gnb_task(void *args_p) { rrc_DU_process_ue_context_modification_request(msg_p, instance); break; - case F1AP_UE_CONTEXT_RELEASE_CMD: - LOG_W(NR_RRC, "Received F1AP_UE_CONTEXT_RELEASE_CMD for processing at the RRC layer of the DU. Processing function " - "implementation is pending\n"); + case F1AP_UE_CONTEXT_RELEASE_REQ: + AssertFatal(false, "F1 UE context release request to be implemented\n"); + break; + + case F1AP_UE_CONTEXT_RELEASE_COMPLETE: + rrc_CU_process_ue_context_release_complete(msg_p); break; /* Messages from X2AP */ @@ -3292,6 +3310,24 @@ rrc_gNB_generate_UECapabilityEnquiry( nr_pdcp_data_req_srb(ctxt_pP->rntiMaybeUEid, DCCH, rrc_gNB_mui++, size, buffer, deliver_pdu_srb_f1, rrc); } +static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id) +{ + DevAssert(deliver_pdu_data != NULL); + gNB_RRC_INST *rrc = deliver_pdu_data; + uint8_t *rrc_container = malloc(size); + AssertFatal(rrc_container != NULL, "out of memory\n"); + memcpy(rrc_container, buf, size); + f1ap_ue_context_release_cmd_t ue_context_release_cmd = { + .rnti = ue_id, /* TODO: proper IDs! */ + .cause = F1AP_CAUSE_RADIO_NETWORK, + .cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release + .srb_id = srb_id, + .rrc_container = rrc_container, + .rrc_container_length = size, + }; + rrc->mac_rrc.ue_context_release_command(&ue_context_release_cmd); +} + //----------------------------------------------------------------------------- /* * Generate the RRC Connection Release to UE. @@ -3306,49 +3342,16 @@ rrc_gNB_generate_RRCRelease( { uint8_t buffer[RRC_BUF_SIZE] = {0}; int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id)); - gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - ue_p->ue_reestablishment_timer = 0; - ue_p->ue_release_timer = 0; - ue_p->ul_failure_timer = 0; - ue_p->ue_release_timer_rrc = 0; LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate RRCRelease (bytes %d)\n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), size); - LOG_D(NR_RRC, - PROTOCOL_NR_RRC_CTXT_UE_FMT" --- PDCP_DATA_REQ/%d Bytes (rrcRelease MUI %d) --->[PDCP][RB %u]\n", - PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), - size, - rrc_gNB_mui, - DCCH); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; - nr_pdcp_data_req_srb(ctxt_pP->rntiMaybeUEid, DCCH, rrc_gNB_mui++, size, buffer, deliver_pdu_srb_f1, rrc); + nr_pdcp_data_req_srb(ctxt_pP->rntiMaybeUEid, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, rrc); - rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(ctxt_pP->instance, ue_context_pP->ue_context.gNB_ue_ngap_id); - ue_context_pP->ue_context.ue_release_timer_rrc = 1; - /* TODO: 38.331 says for RRC Release that the UE should release everything - * after 60ms or if lower layers acked receipt of release. Hence, from the - * gNB POV, we can free the UE's RRC context as soon as we sent the msg. - * Currently, without the F1 interface, the ue_release timer expiration also - * triggers MAC, so we give it some time. If we send an F1 UE Context release - * message, we can free it immediately. The MAC should release it after these - * 60ms, or the ack of the DLSCH transmission. */ - ue_context_pP->ue_context.ue_release_timer_thres_rrc = 5; - LOG_I(RRC, "delaying UE %ld context removal by 5ms\n", ctxt_pP->rntiMaybeUEid); - - if (NODE_IS_CU(rrc->node_type)) { - uint8_t *message_buffer = itti_malloc (TASK_RRC_GNB, TASK_CU_F1, size); - memcpy (message_buffer, buffer, size); - MessageDef *m = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_CMD); - F1AP_UE_CONTEXT_RELEASE_CMD(m).rnti = ctxt_pP->rntiMaybeUEid; - F1AP_UE_CONTEXT_RELEASE_CMD(m).cause = F1AP_CAUSE_RADIO_NETWORK; - F1AP_UE_CONTEXT_RELEASE_CMD(m).cause_value = 10; // 10 = F1AP_CauseRadioNetwork_normal_release - F1AP_UE_CONTEXT_RELEASE_CMD(m).rrc_container = message_buffer; - F1AP_UE_CONTEXT_RELEASE_CMD(m).rrc_container_length = size; - itti_send_msg_to_task(TASK_CU_F1, ctxt_pP->module_id, m); - } + /* UE will be freed after UE context release complete */ } int rrc_gNB_generate_pcch_msg(uint32_t tmsi, uint8_t paging_drx, instance_t instance, uint8_t CC_id){