From 9e45f38fbd95e69197f8ab9887f48fe42e144225 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 25 Nov 2025 17:35:40 +0100 Subject: [PATCH] fix PDU Sesion Release response: add missing PDUSessionResourceReleaseResponseTransfer IE The PDUSessionResourceReleaseResponse message was missing the mandatory pDUSessionResourceReleaseResponseTransfer IE in each released PDU session item. This caused Open5GS to send an error indication. Changes: - Add encode_ngap_pdusession_release_response_transfer() function to properly encode the transfer structure (empty since Secondary RAT Usage Information is optional and not used, per 9.3.4.21) - Always include the mandatory PDUSessionResourceReleasedListRelRes IE - Always encode the pDUSessionResourceReleaseResponseTransfer for each PDU session item - Fix Release Command handler to decode and log Cause from command transfer: instead of incorrectly copying command data to response: the 2 transfer IEs in the Command and the Response messages are different and should not be mixed - Split Command/Response struct type definitions - Add missing includes --- common/utils/telnetsrv/telnetsrv_ci.c | 4 +-- openair2/COMMON/ngap_messages_types.h | 19 ++++++------- openair2/RRC/NR/rrc_gNB_NGAP.c | 4 +-- openair3/NGAP/ngap_gNB_handlers.c | 17 +++++++++-- openair3/NGAP/ngap_gNB_nas_procedures.c | 38 ++++++++++++++++++++----- openair3/NGAP/ngap_msg_includes.h | 2 ++ 6 files changed, 60 insertions(+), 24 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index 8b00d529c5..54c650dd0f 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -348,7 +348,7 @@ static int trigger_ngap_pdu_session_release(char *buf, int debug, telnet_printfu if (sid < 1 || sid > 255) { ERROR_MSG_RET("Invalid pdusession_id(int): %s (must be between 1 and 255)\n", tokens[i]); } - msg->pdusession_release_params[nb_sessions++].pdusession_id = sid; + msg->pdusession_ids[nb_sessions++] = sid; } msg->nb_pdusessions_torelease = nb_sessions; @@ -356,7 +356,7 @@ static int trigger_ngap_pdu_session_release(char *buf, int debug, telnet_printfu if (prnt) { prnt("Triggering NGAP PDU Session Release for gNB_ue_ngap_id=%d: releasing pdusession_id=%d", gNB_ue_ngap_id); for (int i = 0; i < nb_sessions; ++i) { - prnt(" %d,", msg->pdusession_release_params[i].pdusession_id); + prnt(" %d,", msg->pdusession_ids[i]); } prnt("\n"); } diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 92ea721705..ed93cdaadf 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -902,12 +902,6 @@ typedef struct ngap_pdusession_modify_resp_s { pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_modify_resp_t; -typedef struct pdusession_release_s { - /* Unique pdusession_id for the UE. */ - uint8_t pdusession_id; - byte_array_t data; -} pdusession_release_t; - typedef struct ngap_pdusession_release_command_s { /* AMF UE id */ uint64_t amf_ue_ngap_id; @@ -918,14 +912,19 @@ typedef struct ngap_pdusession_release_command_s { /* The NAS PDU should be forwarded by the RRC layer to the NAS layer */ byte_array_t nas_pdu; - /* Number of pdusession to be released in the list */ + // PDU Session Resource to Release List (mandatory) uint16_t nb_pdusessions_torelease; - - /* PDUSession release command */ - pdusession_release_t pdusession_release_params[NGAP_MAX_PDU_SESSION]; + uint16_t pdusession_ids[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_release_command_t; +typedef struct pdusession_release_s { + // PDU Session ID (mandatory) + uint8_t pdusession_id; + // PDU Session Resource Release Response Transfer (mandatory) + byte_array_t pdusession_release_response_transfer; +} pdusession_release_t; + typedef struct ngap_pdusession_release_resp_s { // AMF UE NGAP ID uint64_t amf_ue_ngap_id; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index fdd424df52..a546b5eb33 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1526,9 +1526,9 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_comm cmd->nb_pdusessions_torelease); e1ap_bearer_mod_req_t req = {0}; for (int pdusession = 0; pdusession < cmd->nb_pdusessions_torelease; pdusession++) { - rrc_pdu_session_param_t *pduSession = find_pduSession(&UE->pduSessions, cmd->pdusession_release_params[pdusession].pdusession_id); + rrc_pdu_session_param_t *pduSession = find_pduSession(&UE->pduSessions, cmd->pdusession_ids[pdusession]); if (!pduSession) { - 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_ids[pdusession]); continue; } if (pduSession->status == PDU_SESSION_STATUS_TORELEASE) { diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 95c2dd45a7..a58c98508b 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -1390,9 +1390,20 @@ static int ngap_gNB_handle_pdusession_release_command(sctp_assoc_t assoc_id, uin for (i = 0; i < ie->value.choice.PDUSessionResourceToReleaseListRelCmd.list.count; i++) { NGAP_PDUSessionResourceToReleaseItemRelCmd_t *item_p; item_p = ie->value.choice.PDUSessionResourceToReleaseListRelCmd.list.array[i]; - pdusession_release_t *r = &msg->pdusession_release_params[i]; - r->pdusession_id = item_p->pDUSessionID; - r->data = create_byte_array(item_p->pDUSessionResourceReleaseCommandTransfer.size, item_p->pDUSessionResourceReleaseCommandTransfer.buf); + msg->pdusession_ids[i] = item_p->pDUSessionID; + + /* PDUSessionResourceReleaseCommandTransfer (Mandatory) */ + void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceReleaseCommandTransfer, + item_p->pDUSessionResourceReleaseCommandTransfer); + if (!decoded) { + NGAP_ERROR("Failed to decode PDUSessionResourceReleaseCommandTransfer for PDU Session %d\n", msg->pdusession_ids[i]); + return -1; + } + NGAP_PDUSessionResourceReleaseCommandTransfer_t *transfer = decoded; + ngap_cause_t cause = decode_ngap_cause(&transfer->cause); + NGAP_INFO("PDU Session %d release command: Cause type=%d value=%d\n", msg->pdusession_ids[i], cause.type, cause.value); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceReleaseCommandTransfer, transfer); + free(transfer); } itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 7dd6359b7a..2218155c61 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -594,6 +594,24 @@ static byte_array_t encode_ngap_pdusession_setup_response_transfer(const pdusess return out; } +/** @brief PDU Session Resource Release Response Transfer encoding (9.3.4.21 3GPP TS 38.413) + * The transfer structure contains only an optional Secondary RAT Usage Information IE. + * Since we don't use secondary RAT (MR-DC), we encode an empty structure. */ +static byte_array_t encode_ngap_pdusession_release_response_transfer(void) +{ + NGAP_PDUSessionResourceReleaseResponseTransfer_t pdusessionTransfer = {0}; + + // Encode + asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, + ATS_ALIGNED_CANONICAL_PER, + &asn_DEF_NGAP_PDUSessionResourceReleaseResponseTransfer, + &pdusessionTransfer); + AssertFatal(res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceReleaseResponseTransfer, &pdusessionTransfer); + byte_array_t out = {.buf = res.buffer, .len = res.result.encoded}; + return out; +} + //------------------------------------------------------------------------------ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_resp_t *initial_ctxt_resp_p) //------------------------------------------------------------------------------ @@ -1200,22 +1218,28 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas ie->value.choice.RAN_UE_NGAP_ID = pdusession_release_resp_p->gNB_ue_ngap_id; } - /* optional */ - if (pdusession_release_resp_p->nb_of_pdusessions_released > 0) { + /* PDU Session Resource Released List (mandatory) */ + { asn1cSequenceAdd(out->protocolIEs.list, NGAP_PDUSessionResourceReleaseResponseIEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_PDUSessionResourceReleasedListRelRes; ie->criticality = NGAP_Criticality_ignore; ie->value.present = NGAP_PDUSessionResourceReleaseResponseIEs__value_PR_PDUSessionResourceReleasedListRelRes; - + for (i = 0; i < pdusession_release_resp_p->nb_of_pdusessions_released; i++) { - asn1cSequenceAdd(ie->value.choice.PDUSessionResourceReleasedListRelRes.list, NGAP_PDUSessionResourceReleasedItemRelRes_t, item); + NGAP_PDUSessionResourceReleasedListRelRes_t *list = &ie->value.choice.PDUSessionResourceReleasedListRelRes; + asn1cSequenceAdd(list->list, NGAP_PDUSessionResourceReleasedItemRelRes_t, item); pdusession_release_t *r = &pdusession_release_resp_p->pdusession_release[i]; + /* PDU Session ID (mandatory) */ item->pDUSessionID = r->pdusession_id; - OCTET_STRING_fromBuf(&item->pDUSessionResourceReleaseResponseTransfer, (const char *)r->data.buf, r->data.len); - NGAP_DEBUG("pdusession_release_resp: pdusession ID %ld\n", item->pDUSessionID); + /* PDU Session Resource Release Response Transfer (mandatory) */ + // Empty transfer is valid since Secondary RAT Usage Information is optional and not used + byte_array_t transfer = encode_ngap_pdusession_release_response_transfer(); + OCTET_STRING_fromBuf(&item->pDUSessionResourceReleaseResponseTransfer, (const char *)transfer.buf, transfer.len); + free_byte_array(transfer); + NGAP_DEBUG("PDU Session Resource Release Response: pdusession ID %ld\n", item->pDUSessionID); } } - + if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode release response\n"); /* Encode procedure has failed... */ diff --git a/openair3/NGAP/ngap_msg_includes.h b/openair3/NGAP/ngap_msg_includes.h index 816cdfb979..2a861e2e32 100644 --- a/openair3/NGAP/ngap_msg_includes.h +++ b/openair3/NGAP/ngap_msg_includes.h @@ -58,6 +58,8 @@ #include "NGAP_PDUSessionResourceSetupResponseTransfer.h" #include "NGAP_PDUSessionResourceSetupUnsuccessfulTransfer.h" #include "NGAP_PDUSessionResourceToReleaseItemRelCmd.h" +#include "NGAP_PDUSessionResourceReleaseCommandTransfer.h" +#include "NGAP_PDUSessionResourceReleaseResponseTransfer.h" #include "NGAP_PLMNSupportItem.h" #include "NGAP_ProtocolIE-Field.h" #include "NGAP_QosFlowAddOrModifyResponseItem.h"