Commit 3cfe2e26 authored by Guido Casati's avatar Guido Casati Committed by Robert Schmidt

RRC PDU Session Release: DRBs and PDU session teardown in NGAP PDU Session...

RRC PDU Session Release: DRBs and PDU session teardown in NGAP PDU Session Release Response callback

We need to keep PDU sessions and DRBs in list until the NGAP PDU Session Release Response is sent.

* Introduced find_drb() and remove_drbs_by_pdu_session() helpers to locate
  and clean up DRBs linked to a specific PDU session
* Targeted per-session DRB removal in rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE()
* Ensures DRBs for unaffected PDU sessions remain intact
* Remove unused PDU_SESSION_STATUS_RELEASED status: keeping this status is no longer relevant
  since the PDU sessions are effectively removed from the RRC lists

Closes #867

Also, refactor rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND

3GPP TS 38.413 8.2.2 PDU Session Resource Release says:

> 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.

Therefore, any PDU session in the pdusession_release_params list that is
also present in the RRC list can be set to release, regardless of its status.

The function signature was also updated along with other minor changes.
parent 7d5e20fd
......@@ -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 {
......
......@@ -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:
......
......@@ -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,18 +1599,18 @@ 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);
// 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) {
LOG_E(NR_RRC, "Received NG PDU Session Release Command but no PDU Sessions to release\n");
......
......@@ -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);
......
......@@ -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)
{
......
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment