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 { ...@@ -97,7 +97,6 @@ typedef enum pdu_session_satus_e {
PDU_SESSION_STATUS_TOMODIFY, // ENDC NSA PDU_SESSION_STATUS_TOMODIFY, // ENDC NSA
PDU_SESSION_STATUS_FAILED, PDU_SESSION_STATUS_FAILED,
PDU_SESSION_STATUS_TORELEASE, // to release DRB between eNB and UE PDU_SESSION_STATUS_TORELEASE, // to release DRB between eNB and UE
PDU_SESSION_STATUS_RELEASED
} pdu_session_status_t; } pdu_session_status_t;
typedef struct pdusession_s { typedef struct pdusession_s {
......
...@@ -2880,7 +2880,6 @@ static const char *get_pdusession_status_text(pdu_session_status_t status) ...@@ -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_TOMODIFY: return "to-modify";
case PDU_SESSION_STATUS_FAILED: return "failed"; case PDU_SESSION_STATUS_FAILED: return "failed";
case PDU_SESSION_STATUS_TORELEASE: return "to-release"; 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"; default: AssertFatal(false, "illegal PDU status code %d\n", status); return "illegal";
} }
return "illegal"; return "illegal";
...@@ -3014,7 +3013,7 @@ void *rrc_gnb_task(void *args_p) { ...@@ -3014,7 +3013,7 @@ void *rrc_gnb_task(void *args_p) {
break; break;
case NGAP_PDUSESSION_RELEASE_COMMAND: 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; break;
case NGAP_DL_RAN_STATUS_TRANSFER: 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 ...@@ -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); DevAssert(resp->nb_of_pdusessions_released < NGAP_MAX_PDU_SESSION);
resp->pdusession_release[resp->nb_of_pdusessions_released++].pdusession_id = pdusession->pdusession_id; 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); 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); itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p);
} }
//------------------------------------------------------------------------------ /** @brief Process NG PDU Session Resource Release command (8.2.2 of 3GPP TS 38.413)
int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance) * 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; uint32_t gNB_ue_ngap_id = cmd->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];
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, 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) { 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; return -1;
} }
gNB_RRC_UE_t *UE = &ue_context_p->ue_context; 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, cmd->amf_ue_ngap_id,
gNB_ue_ngap_id, gNB_ue_ngap_id,
cmd->nb_pdusessions_torelease); cmd->nb_pdusessions_torelease);
...@@ -1597,17 +1599,17 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ ...@@ -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); LOG_E(NR_RRC, "Failed to release non-existing PDU Session %d\n", cmd->pdusession_release_params[pdusession].pdusession_id);
continue; 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; continue;
} }
if (pduSession->status == PDU_SESSION_STATUS_ESTABLISHED) { // Set PDU session to release, regardless of the status
LOG_I(NR_RRC, "NG Release PDU Session %d \n", pduSession->param.pdusession_id); 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++]; pdu_session_to_remove_t *release = &req.pduSessionRem[req.numPDUSessionsRem++];
release->sessionId = pduSession->param.pdusession_id; release->sessionId = pduSession->param.pdusession_id;
release->cause.type = E1AP_CAUSE_RADIO_NETWORK; release->cause.type = E1AP_CAUSE_RADIO_NETWORK;
release->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE; release->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE;
pduSession->status = PDU_SESSION_STATUS_TORELEASE; pduSession->status = PDU_SESSION_STATUS_TORELEASE;
}
} }
if (req.numPDUSessionsRem == 0) { if (req.numPDUSessionsRem == 0) {
......
...@@ -78,7 +78,7 @@ void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t ...@@ -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); 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); 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 ...@@ -141,6 +141,62 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio
return added; 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 */ /** @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) 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 ...@@ -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 /// @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); 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 /// @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, bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp,
bool um_on_default_drb, 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