diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index e8820bcc76..e850ce373a 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -97,7 +97,6 @@ typedef enum pdu_session_satus_e { PDU_SESSION_STATUS_TOMODIFY, // ENDC NSA PDU_SESSION_STATUS_FAILED, PDU_SESSION_STATUS_TORELEASE, // to release DRB between eNB and UE - PDU_SESSION_STATUS_RELEASED } pdu_session_status_t; typedef struct pdusession_s { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1e08c9cf25..a6c24fc579 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2880,7 +2880,6 @@ static const char *get_pdusession_status_text(pdu_session_status_t status) case PDU_SESSION_STATUS_TOMODIFY: return "to-modify"; case PDU_SESSION_STATUS_FAILED: return "failed"; case PDU_SESSION_STATUS_TORELEASE: return "to-release"; - case PDU_SESSION_STATUS_RELEASED: return "released"; default: AssertFatal(false, "illegal PDU status code %d\n", status); return "illegal"; } return "illegal"; @@ -3014,7 +3013,7 @@ void *rrc_gnb_task(void *args_p) { break; case NGAP_PDUSESSION_RELEASE_COMMAND: - rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(msg_p, instance); + rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(&NGAP_PDUSESSION_RELEASE_COMMAND(msg_p), RC.nrrrc[instance]); break; case NGAP_DL_RAN_STATUS_TRANSFER: diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 570e3912fa..7bcecb2533 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1562,31 +1562,33 @@ void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE DevAssert(resp->nb_of_pdusessions_released < NGAP_MAX_PDU_SESSION); resp->pdusession_release[resp->nb_of_pdusessions_released++].pdusession_id = pdusession->pdusession_id; } - session->status = PDU_SESSION_STATUS_RELEASED; } } + for (int i = 0; i < resp->nb_of_pdusessions_released; ++i) { + rm_pduSession(&UE->pduSessions, &UE->drbs, resp->pdusession_release[i].pdusession_id); + } + LOG_I(NR_RRC, "NGAP PDUSESSION RELEASE RESPONSE: rrc_ue_id %u release_pdu_sessions %d\n", resp->gNB_ue_ngap_id, resp->nb_of_pdusessions_released); itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p); } -//------------------------------------------------------------------------------ -int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance) -//------------------------------------------------------------------------------ +/** @brief Process NG PDU Session Resource Release command (8.2.2 of 3GPP TS 38.413) + * upon reception the NG-RAN node shall execute the release of the requested PDU sessions. + * For each PDU session to be released the NG-RAN node shall release the corresponding + * resources over Uu and over NG, if any. */ +int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_command_t *cmd, gNB_RRC_INST *rrc) { - uint32_t gNB_ue_ngap_id; - ngap_pdusession_release_command_t *cmd = &NGAP_PDUSESSION_RELEASE_COMMAND(msg_p); - gNB_ue_ngap_id = cmd->gNB_ue_ngap_id; - gNB_RRC_INST *rrc = RC.nrrrc[instance]; + uint32_t gNB_ue_ngap_id = cmd->gNB_ue_ngap_id; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, gNB_ue_ngap_id); if (!ue_context_p) { - LOG_E(NR_RRC, "[gNB %ld] not found ue context gNB_ue_ngap_id %u \n", instance, gNB_ue_ngap_id); + LOG_E(NR_RRC, "[gNB %d] UE context not found for gNB_ue_ngap_id %u \n", rrc->module_id, gNB_ue_ngap_id); return -1; } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - LOG_I(NR_RRC, "PDU Session Release: AMF_UE_NGAP_ID %lu rrc_ue_id %u release_pdusessions %d \n", + LOG_I(NR_RRC, "NG PDU Session Release command: AMF_UE_NGAP_ID=%lu, rrc_ue_id=%u, nb_pdusessions_torelease=%d \n", cmd->amf_ue_ngap_id, gNB_ue_ngap_id, cmd->nb_pdusessions_torelease); @@ -1597,17 +1599,17 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ LOG_E(NR_RRC, "Failed to release non-existing PDU Session %d\n", cmd->pdusession_release_params[pdusession].pdusession_id); continue; } - if (pduSession->status == PDU_SESSION_STATUS_FAILED) { + if (pduSession->status == PDU_SESSION_STATUS_TORELEASE) { + LOG_W(NR_RRC, "PDU Session %d already set to be released\n", pduSession->param.pdusession_id); continue; } - if (pduSession->status == PDU_SESSION_STATUS_ESTABLISHED) { - LOG_I(NR_RRC, "NG Release PDU Session %d \n", pduSession->param.pdusession_id); - pdu_session_to_remove_t *release = &req.pduSessionRem[req.numPDUSessionsRem++]; - release->sessionId = pduSession->param.pdusession_id; - release->cause.type = E1AP_CAUSE_RADIO_NETWORK; - release->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE; - pduSession->status = PDU_SESSION_STATUS_TORELEASE; - } + // Set PDU session to release, regardless of the status + LOG_I(NR_RRC, "Set PDU Session %d to release\n", pduSession->param.pdusession_id); + pdu_session_to_remove_t *release = &req.pduSessionRem[req.numPDUSessionsRem++]; + release->sessionId = pduSession->param.pdusession_id; + release->cause.type = E1AP_CAUSE_RADIO_NETWORK; + release->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE; + pduSession->status = PDU_SESSION_STATUS_TORELEASE; } if (req.numPDUSessionsRem == 0) { diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.h b/openair2/RRC/NR/rrc_gNB_NGAP.h index 91c7722c52..c3f692ff5f 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.h +++ b/openair2/RRC/NR/rrc_gNB_NGAP.h @@ -78,7 +78,7 @@ void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_UECapabilityInformation_t *const ue_cap_info); -int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance); +int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_command_t *cmd, gNB_RRC_INST *rrc); void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 5af84f0399..c636e9e639 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -141,6 +141,62 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio return added; } +static bool eq_drb_pdu_session_id(const void *vval, const void *vit) +{ + const int *id = (const int *)vval; + const drb_t *elem = (const drb_t *)vit; + return elem->pdusession_id == *id; +} + +/** @brief Finds the first DRB with the given PDU session ID. + * @return Pointer to matching drb_t or NULL if not found. */ +static drb_t *find_drb_by_pdusession_id(seq_arr_t *seq, int pdusession_id) +{ + DevAssert(seq); + DevAssert(pdusession_id > 0 && pdusession_id <= NGAP_MAX_PDU_SESSION); + elm_arr_t elm = find_if(seq, &pdusession_id, eq_drb_pdu_session_id); + if (elm.found) + return (drb_t *)elm.it; + return NULL; +} + +/** @brief Removes a DRB from the list + * @param drbs The DRB list + * @param drb Pointer to the DRB to remove */ +static void nr_rrc_rm_drb(seq_arr_t *drbs, drb_t *drb) +{ + DevAssert(drbs); + DevAssert(drb); + LOG_I(NR_RRC, "Removing DRB ID %d (PDU Session ID=%d)\n", drb->drb_id, drb->pdusession_id); + seq_arr_erase_deep(drbs, drb, free_drb); +} + +/** @brief Removes a PDU Session from the list by ID + * Also removes all associated DRBs for this PDU session. + * @return true if successfully removed, false if not found */ +bool rm_pduSession(seq_arr_t *sessions, seq_arr_t *drbs, int pdusession_id) +{ + DevAssert(sessions); + DevAssert(drbs); + + rrc_pdu_session_param_t *session = find_pduSession(sessions, pdusession_id); + + if (session) { + LOG_I(NR_RRC, "Removing PDU Session %d from RRC setup list\n", pdusession_id); + // Remove all associated DRBs first + drb_t *drb; + while ((drb = find_drb_by_pdusession_id(drbs, pdusession_id))) { + nr_rrc_rm_drb(drbs, drb); + } + // Then remove the PDU session + seq_arr_erase_deep(sessions, session, free_pdusession); + return true; + } + + LOG_W(NR_RRC, "pdusession_id=%d not found to remove\n", pdusession_id); + return false; +} + /** @brief Add drb_t item in the UE context list for @param pdusession_id */ drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp) { diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index f6821e314b..a1b09a5b02 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -39,6 +39,10 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio /// @brief get PDU session of UE ue through the DRB drb_id rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id); +/// @brief Remove PDU Session from RRC list +/// Also removes all associated DRBs for this PDU session. +bool rm_pduSession(seq_arr_t *sessions, seq_arr_t *drbs, int pdusession_id); + /// @brief set PDCP configuration in E1 Bearer Context Management message bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp, bool um_on_default_drb,