From a8f8244b09ad0949dbd66706091746882c1bd9bc Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 28 Apr 2025 17:37:08 +0200 Subject: [PATCH 01/18] Fix mutation of input iterators in seq_arr_erase_it The seq_arr_erase_it function was modifying start_it during the free_func loop, which led to incorrectly apply the free_func on the whole array. This commit makes sure the elements "freed" are only those in the range and not the whole seq_arr. * Fixes the logic by introducing a temporary iterator for the free loop, preserving start_it and end_it for correct offset calculations. * Adds a regression test in test_seq_arr to verify that only the selected subrange is erased and that free_func is called exactly on that range. --- common/utils/ds/seq_arr.c | 9 ++++----- common/utils/ds/tests/test_seq_array.c | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/common/utils/ds/seq_arr.c b/common/utils/ds/seq_arr.c index 708552a24e..50a332a16b 100644 --- a/common/utils/ds/seq_arr.c +++ b/common/utils/ds/seq_arr.c @@ -123,11 +123,10 @@ void seq_arr_erase_it(seq_arr_t* arr, void* start_it, void* end_it, void (*free_ return; if (free_func != NULL) { - void* start_it = seq_arr_front(arr); - void* end_it = seq_arr_end(arr); - while (start_it != end_it) { - free_func(start_it); - start_it = seq_arr_next(arr, start_it); + void* it = start_it; + while (it != end_it) { + free_func(it); + it = seq_arr_next(arr, it); } } diff --git a/common/utils/ds/tests/test_seq_array.c b/common/utils/ds/tests/test_seq_array.c index 28a7c98b1e..e06f72c881 100644 --- a/common/utils/ds/tests/test_seq_array.c +++ b/common/utils/ds/tests/test_seq_array.c @@ -36,6 +36,13 @@ static int compar(const void* m0, const void* m1) return 1; } +static int free_func_call_count = 0; + +static void dummy_free_func(void* it) +{ + ++free_func_call_count; +} + int main() { seq_arr_t arr = {0}; @@ -83,6 +90,19 @@ int main() void* it = bsearch(&key, base, nmemb, size, compar); assert(seq_arr_dist(&arr, seq_arr_front(&arr), it) == 4); + // Regression test: erase a partial range only + // Erase 92, 93, 94 (i.e., indices 1 to 3) + int* start = seq_arr_at(&arr, 1); + int* end = seq_arr_at(&arr, 4); + seq_arr_erase_it(&arr, start, end, dummy_free_func); + + // Now values should be: [91, 95, 96, 97, 98, 99] + assert(free_func_call_count == 3); + assert(seq_arr_size(&arr) == 6); + assert(*(int*)seq_arr_at(&arr, 0) == 91); + assert(*(int*)seq_arr_at(&arr, 1) == 95); + assert(*(int*)seq_arr_at(&arr, 5) == 99); + // Free data structure seq_arr_free(&arr, NULL); From 786fada6e659eb6c3dc0d476a996a403c1ef2d11 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 22 Apr 2025 17:34:06 +0200 Subject: [PATCH 02/18] Change pdusession_id_t type to int and remove redundant definition for an ID type --- common/platform_types.h | 1 - openair2/COMMON/gtpv1_u_messages_types.h | 8 ++++---- openair3/ocp-gtpu/gtp_itf.cpp | 3 ++- openair3/ocp-gtpu/gtp_itf.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/platform_types.h b/common/platform_types.h index 8cbd502fda..db692902df 100644 --- a/common/platform_types.h +++ b/common/platform_types.h @@ -226,7 +226,6 @@ typedef struct transport_layer_addr_s { //----------------------------------------------------------------------------- typedef uint32_t teid_t; // tunnel endpoint identifier typedef uint8_t ebi_t; // eps bearer id -typedef uint8_t pdusessionid_t; //----------------------------------------------------------------------------- // diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index 5f12d1e9a2..30471c9c4f 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -163,7 +163,7 @@ typedef struct gtpv1u_gnb_create_tunnel_req_s { int num_tunnels; teid_t outgoing_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; int outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE]; - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; ebi_t incoming_rb_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; transport_layer_addr_t dst_addr[NR_GTPV1U_MAX_BEARERS_PER_UE]; } gtpv1u_gnb_create_tunnel_req_t; @@ -173,13 +173,13 @@ typedef struct gtpv1u_gnb_create_tunnel_resp_s { ue_id_t ue_id; int num_tunnels; teid_t gnb_NGu_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; transport_layer_addr_t gnb_addr; } gtpv1u_gnb_create_tunnel_resp_t; typedef struct gtpv1u_gnb_delete_tunnel_req_s { ue_id_t ue_id; uint8_t num_pdusession; - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; } gtpv1u_gnb_delete_tunnel_req_t; typedef struct gtpv1u_gnb_delete_tunnel_resp_s { @@ -192,7 +192,7 @@ typedef struct gtpv1u_gnb_delete_tunnel_resp_s { typedef struct gtpv1u_DU_buffer_report_req_s { uint32_t buffer_availability; ue_id_t ue_id; - pdusessionid_t pdusession_id; + int pdusession_id; } gtpv1u_DU_buffer_report_req_t; #endif /* GTPV1_U_MESSAGES_TYPES_H_ */ diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index fd571e8d0e..58be5ed638 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -897,7 +897,8 @@ int gtpv1u_delete_all_s1u_tunnel(const instance_t instance, const rnti_t rnti) return newGtpuDeleteAllTunnels(instance, rnti); } -int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id) { +int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id) +{ LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n", instance, ue_id); pthread_mutex_lock(&globGtp.gtp_lock); diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index d5226bb972..7a8c4da627 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -103,7 +103,7 @@ extern "C" { int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id); int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id); - int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id); + int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id); void gtpv1uSendDirect(instance_t instance, ue_id_t ue_id, int bearer_id, uint8_t *buf, size_t len, bool seqNumFlag, bool npduNumFlag); From 00b18f2990f8c969b1e4cb877b9ea4e26876eee7 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 13 May 2025 15:16:07 +0200 Subject: [PATCH 03/18] Cleanup unused and/or long time commented out code in RRC/NGAP * Remove drb_is_active: function is unused and the logic will be later added to another function to add DRBs if necessary * Remove unused NGAP structs and empty TODO functions * Remove unused pdusession_setup_req_t struct definition --- openair2/COMMON/ngap_messages_def.h | 3 - openair2/COMMON/ngap_messages_types.h | 91 ------------------------- openair2/RRC/NR/rrc_gNB_NGAP.c | 14 ---- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 8 --- openair2/RRC/NR/rrc_gNB_radio_bearers.h | 3 - openair3/NGAP/ngap_gNB.c | 8 --- openair3/NGAP/ngap_gNB_nas_procedures.c | 14 ---- openair3/NGAP/ngap_gNB_nas_procedures.h | 6 -- 8 files changed, 147 deletions(-) diff --git a/openair2/COMMON/ngap_messages_def.h b/openair2/COMMON/ngap_messages_def.h index 62498698f2..4f05a564c4 100644 --- a/openair2/COMMON/ngap_messages_def.h +++ b/openair2/COMMON/ngap_messages_def.h @@ -71,9 +71,6 @@ MESSAGE_DEF(NGAP_UE_CTXT_MODIFICATION_FAIL , MESSAGE_PRIORITY_MED, ngap_ue_ctxt_ MESSAGE_DEF(NGAP_PDUSESSION_SETUP_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_setup_resp_t , ngap_pdusession_setup_resp) MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_resp_t , ngap_pdusession_modify_resp) MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, ngap_pdusession_release_resp_t , ngap_pdusession_release_resp) -MESSAGE_DEF(NGAP_PATH_SWITCH_REQ , MESSAGE_PRIORITY_MED, ngap_path_switch_req_t , ngap_path_switch_req) -MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_ACK , MESSAGE_PRIORITY_MED, ngap_path_switch_req_ack_t , ngap_path_switch_req_ack) -MESSAGE_DEF(NGAP_PDUSESSION_MODIFICATION_IND , MESSAGE_PRIORITY_MED, ngap_pdusession_modification_ind_t , ngap_pdusession_modification_ind) /* NGAP -> RRC messages */ MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas ) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index b899bb33e2..c2ba04d53a 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -290,18 +290,6 @@ typedef struct pdusession_setup_s { pdusession_associate_qosflow_t associated_qos_flows[QOSFLOW_MAX_VALUE]; } pdusession_setup_t; -typedef struct pdusession_tobeswitched_s { - /* Unique pdusession_id for the UE. */ - uint8_t pdusession_id; - - /* The transport layer address for the IP packets */ - uint8_t pdu_session_type; - transport_layer_addr_t upf_addr; - - /* S-GW Tunnel endpoint identifier */ - uint32_t gtp_teid; -} pdusession_tobeswitched_t; - typedef struct qos_flow_tobe_modified_s { uint8_t qfi; // 0~63 } qos_flow_tobe_modified_t; @@ -640,13 +628,6 @@ typedef struct ngap_paging_ind_s { ngap_paging_priority_t paging_priority; } ngap_paging_ind_t; -typedef struct { - /* Unique pdusession_id for the UE. */ - int pdusession_id; - byte_array_t nas_pdu; - byte_array_t pdusessionTransfer; -} pdusession_setup_req_t; - typedef struct ngap_pdusession_setup_req_s { /* UE id for initial connection to NGAP */ uint32_t gNB_ue_ngap_id; @@ -682,78 +663,6 @@ typedef struct ngap_pdusession_setup_resp_s { pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_setup_resp_t; -typedef struct ngap_path_switch_req_s { - uint32_t gNB_ue_ngap_id; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_of_pdusessions; - - /* list of pdusession setup-ed by RRC layers */ - pdusession_setup_t pdusessions_tobeswitched[NGAP_MAX_PDU_SESSION]; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - nr_guami_t ue_guami; - - uint16_t ue_initial_id; - /* Security algorithms */ - ngap_security_capabilities_t security_capabilities; - -} ngap_path_switch_req_t; - -typedef struct ngap_path_switch_req_ack_s { - - /* UE id for initial connection to NGAP */ - uint16_t ue_initial_id; - - uint32_t gNB_ue_ngap_id; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - /* UE aggregate maximum bitrate */ - ngap_ambr_t ue_ambr; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_pdusessions_tobeswitched; - - /* list of pdusession to be switched by RRC layers */ - pdusession_tobeswitched_t pdusessions_tobeswitched[NGAP_MAX_PDU_SESSION]; - - /* Number of pdusessions to be released by RRC */ - uint8_t nb_pdusessions_tobereleased; - - /* list of pdusessions to be released */ - pdusession_failed_t pdusessions_tobereleased[NGAP_MAX_PDU_SESSION]; - - /* Security key */ - int next_hop_chain_count; - uint8_t next_security_key[SECURITY_KEY_LENGTH]; - -} ngap_path_switch_req_ack_t; - -typedef struct ngap_pdusession_modification_ind_s { - - uint32_t gNB_ue_ngap_id; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_of_pdusessions_tobemodified; - - uint8_t nb_of_pdusessions_nottobemodified; - - /* list of pdusession setup-ed by RRC layers */ - pdusession_setup_t pdusessions_tobemodified[NGAP_MAX_PDU_SESSION]; - - pdusession_setup_t pdusessions_nottobemodified[NGAP_MAX_PDU_SESSION]; - - uint16_t ue_initial_id; - -} ngap_pdusession_modification_ind_t; - // NGAP --> RRC messages typedef struct ngap_ue_release_command_s { diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 9fd4306962..7b0261832c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -807,10 +807,6 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE } resp->nb_of_pdusessions = pdu_sessions_done; resp->nb_of_pdusessions_failed = pdu_sessions_failed; - // } else { - // LOG_D(NR_RRC,"xid does not corresponds (context pdu_sessions index %d, status %d, xid %d/%d) \n ", - // pdusession, UE->pdusession[pdusession].status, xid, UE->pdusession[pdusession].xid); - // } } if ((pdu_sessions_done > 0 || pdu_sessions_failed)) { @@ -1457,16 +1453,6 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ return 0; } -void nr_rrc_rx_tx(void) { - // check timers - - // check if UEs are lost, to remove them from upper layers - - // - -} - -/*------------------------------------------------------------------------------*/ int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance) { for (uint16_t tai_size = 0; tai_size < NGAP_PAGING_IND(msg_p).tai_size; tai_size++) { diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index e22ee7ffd6..fa504b9dc4 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -208,11 +208,3 @@ int get_number_active_drbs(gNB_RRC_UE_t *ue) n++; return n; } - -bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) -{ - drb_t *drb = get_drb(ue, drb_id); - if (drb == NULL) - return DRB_INACTIVE; - return drb->status != DRB_INACTIVE; -} diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index 4a249496ff..248b6f8082 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -65,9 +65,6 @@ uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue); /// @brief returns the number of active DRBs for this UE int get_number_active_drbs(gNB_RRC_UE_t *ue); -/// @brief check if DRB with ID drb_id of UE ue is active -bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id); - /// @brief retrieve PDU session of UE ue with ID id, optionally creating it if /// create is true rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create); diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index ae8d806e18..8edb5c3aa3 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -344,14 +344,6 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { ngap_gNB_nas_non_delivery_ind(instance, &NGAP_NAS_NON_DELIVERY_IND(received_msg)); break; - case NGAP_PATH_SWITCH_REQ: - ngap_gNB_path_switch_req(instance, &NGAP_PATH_SWITCH_REQ(received_msg)); - break; - - case NGAP_PDUSESSION_MODIFICATION_IND: - ngap_gNB_generate_PDUSESSION_Modification_Indication(instance, &NGAP_PDUSESSION_MODIFICATION_IND(received_msg)); - break; - case NGAP_UE_CONTEXT_RELEASE_COMPLETE: ngap_ue_context_release_complete(instance, &NGAP_UE_CONTEXT_RELEASE_COMPLETE(received_msg)); break; diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index b00ce13f32..5ae65f1c42 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -1225,17 +1225,3 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas return 0; } -int ngap_gNB_path_switch_req(instance_t instance, ngap_path_switch_req_t *path_switch_req_p) -//------------------------------------------------------------------------------ -{ - //TODO - - return 0; -} - -int ngap_gNB_generate_PDUSESSION_Modification_Indication(instance_t instance, ngap_pdusession_modification_ind_t *pdusession_modification_ind) -//----------------------------------------------------------------------------- -{ - //TODO - return 0; -} diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.h b/openair3/NGAP/ngap_gNB_nas_procedures.h index 3cd03838b4..5189e6b311 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.h +++ b/openair3/NGAP/ngap_gNB_nas_procedures.h @@ -63,10 +63,4 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_release_resp_t *pdusession_release_resp_p); -int ngap_gNB_path_switch_req(instance_t instance, - ngap_path_switch_req_t *path_switch_req_p); - -int ngap_gNB_generate_PDUSESSION_Modification_Indication( - instance_t instance, ngap_pdusession_modification_ind_t *pdusession_modification_ind); - #endif /* NGAP_GNB_NAS_PROCEDURES_H_ */ From 78feea10bb1022fb70fa13d5550a456c1979d2aa Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 22 Apr 2025 15:44:06 +0200 Subject: [PATCH 04/18] Add function to deep copy pdusession_t struct --- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 9 +++++++++ openair2/RRC/NR/rrc_gNB_radio_bearers.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index fa504b9dc4..7bed45ee64 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -32,6 +32,15 @@ #include "oai_asn1.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h" +/** @brief Deep copy pdusession_t */ +void cp_pdusession(pdusession_t *dst, const pdusession_t *src) +{ + // Shallow copy + *dst = *src; + // nas_pdu + dst->nas_pdu = copy_byte_array(src->nas_pdu); +} + rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create) { int j; diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index 248b6f8082..1eac60a609 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -78,4 +78,7 @@ void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_S /// @brief set PDCP configuration in a bearer context management message void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb); +/// @brief Deep copy an instance of struct pdusession_t +void cp_pdusession(pdusession_t *dst, const pdusession_t *src); + #endif From 93936ffd9b189d973d5c3caf35d1e0237bbe5f6f Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 13 May 2025 21:31:43 +0200 Subject: [PATCH 05/18] Fix comment in transport_layer_addr_t --- common/platform_types.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/common/platform_types.h b/common/platform_types.h index db692902df..8a8868226a 100644 --- a/common/platform_types.h +++ b/common/platform_types.h @@ -208,14 +208,9 @@ typedef struct nsa_msg_t { } nsa_msg_t; typedef struct transport_layer_addr_s { - /** - * Transport Layer Address as a bitstring: - * - 32 bits for IPv4 (RFC 791), - * - 128 bits for IPv6 (RFC 2460), - * - 160 bits for both IPv4 and IPv6, with IPv4 in the first 32 bits. - * The S1AP/NGAP layer forwards this address (bitstring<1..160>) - * to S1-U/NG-U without interpreting it. - */ + /** Transport Layer Address in bytes: + * - 4 bytes for IPv4 (RFC 791), 16 bytes for IPv6 (RFC 2460), + * - 20 bytes for both IPv4 and IPv6, with IPv4 in the first 4 bytes. */ uint8_t length; /// Buffer: address in network byte order uint8_t buffer[20]; From 32e5f972e95368b7d6f96c6e06ff5ac9ad38382d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 13 May 2025 21:57:25 +0200 Subject: [PATCH 06/18] Refactor f1u_tunnel_t into gtpu_tunnel_t This struct is used in different layers, e.g. RRC, NGAP: therefore it has been moved to platform_types.h. Also, the struct holds the tunnel endpoint configuration for any GTP-U tunnel, therefore the f1u prefix is not accurate and was updated to a more generic gtpu. --- common/platform_types.h | 8 ++++++++ openair2/RRC/NR/nr_rrc_defs.h | 14 ++------------ openair2/RRC/NR/rrc_gNB.c | 4 ++-- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/common/platform_types.h b/common/platform_types.h index 8a8868226a..b31474d475 100644 --- a/common/platform_types.h +++ b/common/platform_types.h @@ -216,6 +216,14 @@ typedef struct transport_layer_addr_s { uint8_t buffer[20]; } transport_layer_addr_t; +/** @brief GTP tunnel configuration */ +typedef struct { + // Tunnel endpoint identifier + uint32_t teid; + // Transport layer address + transport_layer_addr_t addr; +} gtpu_tunnel_t; + //----------------------------------------------------------------------------- // GTPV1U TYPES //----------------------------------------------------------------------------- diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index f2434eceaf..9998562b61 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -106,16 +106,6 @@ typedef struct pdu_session_param_s { ngap_cause_t cause; } rrc_pdu_session_param_t; -/** - * @brief F1-U tunnel configuration -*/ -typedef struct f1u_tunnel_s { - /* F1-U Tunnel Endpoint Identifier (on DU side) */ - uint32_t teid; - /* Downlink F1-U Transport Layer (on DU side) */ - transport_layer_addr_t addr; -} f1u_tunnel_t; - typedef struct drb_s { int status; int drb_id; @@ -145,9 +135,9 @@ typedef struct drb_s { } ext1; } pdcp_config; // F1-U Downlink Tunnel Config (on DU side) - f1u_tunnel_t du_tunnel_config; + gtpu_tunnel_t du_tunnel_config; // F1-U Uplink Tunnel Config (on CU-UP side) - f1u_tunnel_t cuup_tunnel_config; + gtpu_tunnel_t cuup_tunnel_config; } drb_t; typedef enum { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f69e03b810..f47700ae9a 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2007,7 +2007,7 @@ static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_b /** * @brief Store F1-U DL TL and TEID in RRC */ -static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p) +static void f1u_dl_gtp_update(gtpu_tunnel_t *f1u, const f1ap_up_tnl_t *p) { f1u->teid = p->teid; memcpy(&f1u->addr.buffer, &p->tl_address, sizeof(uint8_t) * 4); @@ -2031,7 +2031,7 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R /* * @brief Store F1-U UL TEID and address in RRC */ -static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p) +static void f1u_ul_gtp_update(gtpu_tunnel_t *f1u, const up_params_t *p) { f1u->teid = p->tl_info.teId; memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4); From b86ae96c66933d0415501b6f0805aed01c8f4667 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 13 May 2025 22:54:00 +0200 Subject: [PATCH 07/18] Merge f1u_dl_gtp_update and f1u_ul_gtp_update in f1u_gtp_update * The 2 functions do the same thing, the only difference is the direction (DL/UL) --- openair2/RRC/NR/rrc_gNB.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f47700ae9a..d71be33fcb 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2004,14 +2004,13 @@ static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_b drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid; } -/** - * @brief Store F1-U DL TL and TEID in RRC -*/ -static void f1u_dl_gtp_update(gtpu_tunnel_t *f1u, const f1ap_up_tnl_t *p) +static gtpu_tunnel_t f1u_gtp_update(uint32_t teid, const in_addr_t addr) { - f1u->teid = p->teid; - memcpy(&f1u->addr.buffer, &p->tl_address, sizeof(uint8_t) * 4); - f1u->addr.length = sizeof(in_addr_t); + gtpu_tunnel_t out = {0}; + out.teid = teid; + memcpy(&out.addr.buffer, &addr, 4); + out.addr.length = sizeof(addr); + return out; } /** @@ -2024,20 +2023,10 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R AssertFatal(drb_f1->up_dl_tnl_length == 1, "can handle only one UP param\n"); AssertFatal(drb_f1->drb_id < MAX_DRBS_PER_UE, "illegal DRB ID %ld\n", drb_f1->drb_id); drb_t *drb = get_drb(ue, drb_f1->drb_id); - f1u_dl_gtp_update(&drb->du_tunnel_config, &drb_f1->up_dl_tnl[0]); + drb->du_tunnel_config = f1u_gtp_update(drb_f1->up_dl_tnl[0].teid, drb_f1->up_dl_tnl[0].tl_address); } } -/* - * @brief Store F1-U UL TEID and address in RRC - */ -static void f1u_ul_gtp_update(gtpu_tunnel_t *f1u, const up_params_t *p) -{ - f1u->teid = p->tl_info.teId; - memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4); - f1u->addr.length = sizeof(in_addr_t); -} - /* \brief use list of DRBs and send the corresponding bearer update message via * E1 to the CU of this UE. Also updates TEID info internally */ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) @@ -2470,7 +2459,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp // numUpParam only relevant in F1, but not monolithic AssertFatal(drb_config->numUpParam <= 1, "can only up to one UP param\n"); drb_t *drb = get_drb(UE, drb_config->id); - f1u_ul_gtp_update(&drb->cuup_tunnel_config, &drb_config->UpParamList[0]); + UP_TL_information_t *tl_info = &drb_config->UpParamList[0].tl_info; + drb->cuup_tunnel_config = f1u_gtp_update(tl_info->teId, tl_info->tlAddress); } } From 4ec498c9960b0b3d2213b91893b913c3fbbf694d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Jun 2025 15:17:29 +0200 Subject: [PATCH 08/18] Refactor tunnel endpoint struct members in pdu_session_t Motivation: Clarify the role of GTP tunnel endpoint IDs in PDU session handling. Previously, the struct members (gNB_teid_N3, UPF_teid_N3, etc.) were confusingly named and duplicated with separate transport-layer address fields. This refactoring replaces these with explicit n3_incoming and n3_outgoing members using gtpu_tunnel_t. This aligns with GTP conventions: "incoming TEID" refers to the TEID received from the remote peer (UPF on N3), while "outgoing TEID" is the TEID sent by the local entity (NG-RAN on N3) to the remote peer. Benefits: * Improves readability and clarity of the code * Reduces redundant struct members, i.e. remove UPF_teid_N3, UPF_addr_N3 * Aligns naming with 3GPP conventions for transport layer tunnels Changes: * Replace gtp_addr_N3, gNB_teid_N3, gtp_teid, upf_addr with n3_incoming and n3_outgoing * Update all related code to use the new struct members * Aligns naming with 3GPP conventions for transport layer tunnels --- openair2/COMMON/ngap_messages_types.h | 13 ++++------- .../RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c | 4 ++-- openair2/RRC/NR/rrc_gNB.c | 6 ++--- openair2/RRC/NR/rrc_gNB_NGAP.c | 23 ++++++++----------- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index c2ba04d53a..e30c0bab79 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -249,15 +249,10 @@ typedef struct pdusession_s { pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; /* The transport layer address for the IP packets */ pdu_session_type_t pdu_session_type; - transport_layer_addr_t upf_addr; - /* Outgoing (UL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gtp_teid; - /* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gNB_teid_N3; - transport_layer_addr_t gNB_addr_N3; - /* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t UPF_teid_N3; - transport_layer_addr_t UPF_addr_N3; + // NG-RAN endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_outgoing; + // UPF endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_incoming; nssai_t nssai; } pdusession_t; diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c index 31d96433c1..158c126c39 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c @@ -65,8 +65,8 @@ bool read_gtp_sm(void * data) int nb_pdu_session = ue_context_p->ue_context.nb_of_pdusessions; if (nb_pdu_session > 0) { int nb_pdu_idx = nb_pdu_session - 1; - gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gNB_teid_N3; - gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.UPF_teid_N3; + gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.n3_outgoing.teid; + gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.n3_incoming.teid; // TODO: one PDU session has multiple QoS Flow int nb_qos_flow = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos; if (nb_qos_flow > 0) { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index d71be33fcb..cda981ee34 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2449,9 +2449,9 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id); continue; } - rrc_pdu->param.gNB_teid_N3 = e1_pdu->tl_info.teId; - memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4); - rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t); + rrc_pdu->param.n3_outgoing.teid = e1_pdu->tl_info.teId; + memcpy(&rrc_pdu->param.n3_outgoing.addr.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4); + rrc_pdu->param.n3_outgoing.addr.length = sizeof(in_addr_t); // save the tunnel address for the DRBs for (int i = 0; i < e1_pdu->numDRBSetup; i++) { diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 7b0261832c..e1e5e046d9 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -283,12 +283,11 @@ static int decodePDUSessionResourceSetup(pdusession_t *session) NGAP_GTPTunnel_t *gTPTunnel_p = pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel; /* Set the transport layer address */ - memcpy(session->upf_addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); - - session->upf_addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused; + memcpy(session->n3_incoming.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); + session->n3_incoming.addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused; /* GTP tunnel endpoint ID */ - OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, session->gtp_teid); + OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, session->n3_incoming.teid); } break; @@ -386,8 +385,8 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession : SECURITY_NOT_NEEDED; sec->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? SECURITY_REQUIRED : SECURITY_NOT_NEEDED; - pdu->UP_TL_information.teId = session->gtp_teid; - memcpy(&pdu->UP_TL_information.tlAddress, session->upf_addr.buffer, sizeof(in_addr_t)); + pdu->UP_TL_information.teId = session->n3_incoming.teid; + memcpy(&pdu->UP_TL_information.tlAddress, session->n3_incoming.addr.buffer, sizeof(in_addr_t)); /* we assume for the moment one DRB per PDU session. Activate the bearer, * and configure in RRC. */ @@ -582,9 +581,9 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_ if (session->status == PDU_SESSION_STATUS_DONE) { pdu_sessions_done++; resp->pdusessions[pdusession].pdusession_id = session->param.pdusession_id; - resp->pdusessions[pdusession].gtp_teid = session->param.gNB_teid_N3; + resp->pdusessions[pdusession].gtp_teid = session->param.n3_outgoing.teid; memcpy(resp->pdusessions[pdusession].gNB_addr.buffer, - session->param.gNB_addr_N3.buffer, + session->param.n3_outgoing.addr.buffer, sizeof(resp->pdusessions[pdusession].gNB_addr.buffer)); resp->pdusessions[pdusession].gNB_addr.length = 4; // Fixme: IPv4 hard coded here resp->pdusessions[pdusession].nb_of_qos_flow = session->param.nb_qos; @@ -777,10 +776,10 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE pdusession_setup_t *tmp = &resp->pdusessions[pdu_sessions_done]; tmp->pdusession_id = session->param.pdusession_id; tmp->nb_of_qos_flow = session->param.nb_qos; - tmp->gtp_teid = session->param.gNB_teid_N3; + tmp->gtp_teid = session->param.n3_outgoing.teid; tmp->pdu_session_type = session->param.pdu_session_type; - tmp->gNB_addr.length = session->param.gNB_addr_N3.length; - memcpy(tmp->gNB_addr.buffer, session->param.gNB_addr_N3.buffer, tmp->gNB_addr.length); + tmp->gNB_addr.length = session->param.n3_outgoing.addr.length; + memcpy(tmp->gNB_addr.buffer, session->param.n3_outgoing.addr.buffer, tmp->gNB_addr.length); for (int qos_flow_index = 0; qos_flow_index < tmp->nb_of_qos_flow; qos_flow_index++) { tmp->associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; tmp->associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; @@ -1091,8 +1090,6 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins } // Save new pdu session parameters, qos, upf addr, teid decodePDUSessionResourceModify(&sess->param, UE->pduSession[i].param.pdusessionTransfer); - sess->param.UPF_addr_N3 = sessMod->upf_addr; - sess->param.UPF_teid_N3 = sessMod->gtp_teid; } } From a36de80e6f35f68c9b3f55bd29055aade59cc55e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Jun 2025 15:44:13 +0200 Subject: [PATCH 09/18] Simplify pdu session structs members naming to pdusession Rename the struct members: `pdusession_param` to `pdusession` in NGAP Initial Context Setup Request `pdusession_setup_params` in `ngap_pdusession_setup_req_t` `pdusession_modify_params` and `ngap_pdusession_modify_req_t` --- openair2/COMMON/ngap_messages_types.h | 6 +++--- openair2/RRC/NR/rrc_gNB_NGAP.c | 14 ++++++-------- openair3/NGAP/ngap_gNB_handlers.c | 22 +++++++++++----------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index e30c0bab79..6bd2ed5a5f 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -589,7 +589,7 @@ typedef struct ngap_initial_context_setup_req_s { /* Number of pdusession to be setup in the list */ uint8_t nb_of_pdusessions; /* list of pdusession to be setup by RRC layers */ - pdusession_t pdusession_param[NGAP_MAX_PDU_SESSION]; + pdusession_t pdusession[NGAP_MAX_PDU_SESSION]; /* Mobility Restriction List */ uint8_t mobility_restriction_flag; @@ -638,7 +638,7 @@ typedef struct ngap_pdusession_setup_req_s { uint8_t nb_pdusessions_tosetup; /* E RAB setup request */ - pdusession_t pdusession_setup_params[NGAP_MAX_PDU_SESSION]; + pdusession_t pdusession[NGAP_MAX_PDU_SESSION]; /* UE Aggregated Max Bitrates */ ngap_ambr_t ueAggMaxBitRate; @@ -694,7 +694,7 @@ typedef struct ngap_pdusession_modify_req_s { uint8_t nb_pdusessions_tomodify; /* pdu session modify request */ - pdusession_t pdusession_modify_params[NGAP_MAX_PDU_SESSION]; + pdusession_t pdusession[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_modify_req_t; typedef struct ngap_pdusession_modify_resp_s { diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index e1e5e046d9..42fe17fec9 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -479,7 +479,7 @@ static void send_ngap_initial_context_setup_resp_fail(instance_t instance, resp->gNB_ue_ngap_id = msg->gNB_ue_ngap_id; for (int i = 0; i < msg->nb_of_pdusessions; i++) { - fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession_param[i].pdusession_id, cause); + fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession[i].pdusession_id, cause); } resp->nb_of_pdusessions = 0; resp->nb_of_pdusessions_failed = msg->nb_of_pdusessions; @@ -521,7 +521,7 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t UE->initial_pdus = calloc(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); AssertFatal(UE->initial_pdus != NULL, "out of memory\n"); for (int i = 0; i < UE->n_initial_pdu; ++i) - UE->initial_pdus[i] = req->pdusession_param[i]; + UE->initial_pdus[i] = req->pdusession[i]; } /* security */ @@ -855,9 +855,7 @@ static void send_ngap_pdu_session_setup_resp_fail(instance_t instance, ngap_pdus resp->nb_of_pdusessions_failed = msg->nb_pdusessions_tosetup; resp->nb_of_pdusessions = 0; for (int i = 0; i < resp->nb_of_pdusessions_failed; ++i) { - fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], - msg->pdusession_setup_params[i].pdusession_id, - cause); + fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession[i].pdusession_id, cause); } itti_send_msg_to_task(TASK_NGAP, instance, msg_resp); } @@ -903,7 +901,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins // At least one because marking one as existing, and setting up another, that // might be more work than is worth it. See 8.2.1.4 in 38.413 for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) { - const pdusession_t *p = &msg->pdusession_setup_params[i]; + const pdusession_t *p = &msg->pdusession[i]; rrc_pdu_session_param_t *exist = find_pduSession(UE, p->pdusession_id, false /* don't create */); if (exist) { LOG_E(NR_RRC, "UE %d: already has existing PDU session %d rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id, p->pdusession_id); @@ -936,7 +934,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return; } - if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRate.br_dl)) { + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession, msg->ueAggMaxBitRate.br_dl)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE}; @@ -1064,7 +1062,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins bool all_failed = true; for (int i = 0; i < req->nb_pdusessions_tomodify; i++) { rrc_pdu_session_param_t *sess; - const pdusession_t *sessMod = req->pdusession_modify_params + i; + const pdusession_t *sessMod = req->pdusession + i; for (sess = UE->pduSession; sess < UE->pduSession + UE->nb_of_pdusessions; sess++) if (sess->param.pdusession_id == sessMod->pdusession_id) break; diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 3f6b718861..6737879e7f 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -762,13 +762,13 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 for (i = 0; i < ie->value.choice.PDUSessionResourceSetupListCxtReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemCxtReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.array[i]; - msg->pdusession_param[i].pdusession_id = item_p->pDUSessionID; - msg->pdusession_param[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); if (item_p->nAS_PDU) { - msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); } OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; - msg->pdusession_param[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + msg->pdusession[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } } @@ -936,14 +936,14 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 for (int i = 0; i < ie->value.choice.PDUSessionResourceSetupListSUReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemSUReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListSUReq.list.array[i]; - msg->pdusession_setup_params[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; // S-NSSAI - msg->pdusession_setup_params[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; - msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); - msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); + msg->pdusession[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); @@ -1116,13 +1116,13 @@ static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint for (int i = 0; i < ie->value.choice.PDUSessionResourceModifyListModReq.list.count; i++) { NGAP_PDUSessionResourceModifyItemModReq_t *item_p = ie->value.choice.PDUSessionResourceModifyListModReq.list.array[i]; - msg->pdusession_modify_params[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; // check for the NAS PDU if (item_p->nAS_PDU != NULL && item_p->nAS_PDU->size > 0) { - msg->pdusession_modify_params[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); OCTET_STRING_t *transfer = &item_p->pDUSessionResourceModifyRequestTransfer; - msg->pdusession_modify_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + msg->pdusession[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } else { LOG_W(NGAP, "received pdu session modify with void content for UE %u, pdu session %lu\n", msg->gNB_ue_ngap_id, item_p->pDUSessionID); continue; From 5ff24cce71e23ecad2e0799507ce529af2270452 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Jun 2025 16:19:15 +0200 Subject: [PATCH 10/18] Refactor pdusession_t Definitions Motivation: The previous code had overlapping and partially inconsiste definitions of `pdusession_t` and related structures across NGAP and RRC. This struct type was used for either the data stored in the UE context and the NGAP message IEs holding the PDU session to setup/modify information. This patch aims to separte the `pdusession_t` in RRC, where it logically belongs, since RRC owns the state of the PDU sessions. NGAP should only deal with protocol messages, i.e. enc/dec and transfer structures to RRC. This clarifies module ownership. This also makes the code easier to maintain. Changes: * Moved `pdusession_t` definition from NGAP (`ngap_messages_types.h`) to RRC (`nr_rrc_defs.h`) * Added a simpler `pdusession_resource_item_t` structure to NGAP for use in protocol messages * Adjusted NGAP structures accordingly (Initial Context Setup, PDU Session Setup Request, and PDU Session Modify Request). * do decodePDUSessionResourceSetup to decode the NGAP IEs holding PDU session information and store what necessary in the UE context PDU Session IE: NOTE this changes were necessary since previously this function was acting on the common NGAP/RRC pdu_session_t struct --- openair2/COMMON/ngap_messages_types.h | 44 ++++++++------------------- openair2/RRC/NR/nr_rrc_defs.h | 25 +++++++++++++++ openair2/RRC/NR/rrc_gNB_NGAP.c | 28 +++++++++-------- 3 files changed, 54 insertions(+), 43 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 6bd2ed5a5f..db7529b797 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -231,31 +231,6 @@ typedef struct ngap_mobility_restriction_s{ ngap_plmn_identity_t serving_plmn; }ngap_mobility_restriction_t; -typedef enum pdu_session_type_e { - PDUSessionType_ipv4 = 0, - PDUSessionType_ipv6 = 1, - PDUSessionType_ipv4v6 = 2, - PDUSessionType_ethernet = 3, - PDUSessionType_unstructured = 4 -}pdu_session_type_t; - -typedef struct pdusession_s { - /* Unique pdusession_id for the UE. */ - int pdusession_id; - byte_array_t nas_pdu; - byte_array_t pdusessionTransfer; - uint8_t nb_qos; - /* Quality of service for this pdusession */ - pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; - /* The transport layer address for the IP packets */ - pdu_session_type_t pdu_session_type; - // NG-RAN endpoint of the NG-U (N3) transport bearer - gtpu_tunnel_t n3_outgoing; - // UPF endpoint of the NG-U (N3) transport bearer - gtpu_tunnel_t n3_incoming; - nssai_t nssai; -} pdusession_t; - typedef enum pdusession_qosflow_mapping_ind_e{ QOSFLOW_MAPPING_INDICATION_UL = 0, QOSFLOW_MAPPING_INDICATION_DL = 1, @@ -563,6 +538,13 @@ typedef struct ngap_downlink_nas_s { byte_array_t nas_pdu; } ngap_downlink_nas_t; +/* PDU Session Resource Setup/Modify Request Item */ +typedef struct { + int pdusession_id; + byte_array_t nas_pdu; + nssai_t nssai; + byte_array_t pdusessionTransfer; +} pdusession_resource_item_t; typedef struct ngap_initial_context_setup_req_s { /* UE id for initial connection to NGAP */ @@ -588,8 +570,8 @@ typedef struct ngap_initial_context_setup_req_s { /* Number of pdusession to be setup in the list */ uint8_t nb_of_pdusessions; - /* list of pdusession to be setup by RRC layers */ - pdusession_t pdusession[NGAP_MAX_PDU_SESSION]; + // PDU Session Resource Setup Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; /* Mobility Restriction List */ uint8_t mobility_restriction_flag; @@ -637,8 +619,8 @@ typedef struct ngap_pdusession_setup_req_s { /* Number of pdusession to be setup in the list */ uint8_t nb_pdusessions_tosetup; - /* E RAB setup request */ - pdusession_t pdusession[NGAP_MAX_PDU_SESSION]; + // PDU Session Resource Setup Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; /* UE Aggregated Max Bitrates */ ngap_ambr_t ueAggMaxBitRate; @@ -693,8 +675,8 @@ typedef struct ngap_pdusession_modify_req_s { /* Number of pdusession to be modify in the list */ uint8_t nb_pdusessions_tomodify; - /* pdu session modify request */ - pdusession_t pdusession[NGAP_MAX_PDU_SESSION]; + // PDU Session Resource Modify Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_modify_req_t; typedef struct ngap_pdusession_modify_resp_s { diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 9998562b61..89fcfe7561 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -99,6 +99,31 @@ typedef enum pdu_session_satus_e { PDU_SESSION_STATUS_RELEASED } pdu_session_status_t; +typedef enum pdu_session_type_e { + PDUSessionType_ipv4 = 0, + PDUSessionType_ipv6 = 1, + PDUSessionType_ipv4v6 = 2, + PDUSessionType_ethernet = 3, + PDUSessionType_unstructured = 4 +}pdu_session_type_t; + +typedef struct pdusession_s { + /* Unique pdusession_id for the UE. */ + int pdusession_id; + byte_array_t nas_pdu; + byte_array_t pdusessionTransfer; + uint8_t nb_qos; + /* Quality of service for this pdusession */ + pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; + /* The transport layer address for the IP packets */ + pdu_session_type_t pdu_session_type; + // NG-RAN endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_outgoing; + // UPF endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_incoming; + nssai_t nssai; +} pdusession_t; + typedef struct pdu_session_param_s { pdusession_t param; pdu_session_status_t status; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 42fe17fec9..1bb60df9bc 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -254,7 +254,7 @@ static void fill_qos(NGAP_QosFlowSetupRequestList_t *qos, pdusession_t *session) session->nb_qos = qos->list.count; } -static int decodePDUSessionResourceSetup(pdusession_t *session) +static int decodePDUSessionResourceSetup(pdusession_t *out, const pdusession_resource_item_t *session) { NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = NULL; asn_codec_ctx_t st = {.max_stack_size = 100 * 1000}; @@ -283,11 +283,11 @@ static int decodePDUSessionResourceSetup(pdusession_t *session) NGAP_GTPTunnel_t *gTPTunnel_p = pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel; /* Set the transport layer address */ - memcpy(session->n3_incoming.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); - session->n3_incoming.addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused; + memcpy(out->n3_incoming.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); + out->n3_incoming.addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused; /* GTP tunnel endpoint ID */ - OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, session->n3_incoming.teid); + OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, out->n3_incoming.teid); } break; @@ -302,7 +302,7 @@ static int decodePDUSessionResourceSetup(pdusession_t *session) /* mandatory PDUSessionType */ case NGAP_ProtocolIE_ID_id_PDUSessionType: - session->pdu_session_type = (uint8_t)pdusessionTransfer_ies->value.choice.PDUSessionType; + out->pdu_session_type = (uint8_t)pdusessionTransfer_ies->value.choice.PDUSessionType; break; /* optional SecurityIndication */ @@ -315,7 +315,7 @@ static int decodePDUSessionResourceSetup(pdusession_t *session) /* mandatory QosFlowSetupRequestList */ case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: - fill_qos(&pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList, session); + fill_qos(&pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList, out); break; /* optional CommonNetworkInstance */ @@ -365,7 +365,6 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession session->nas_pdu = sessions[i].nas_pdu; session->pdusessionTransfer = sessions[i].pdusessionTransfer; session->nssai = sessions[i].nssai; - decodePDUSessionResourceSetup(session); bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; security_information_t *secInfo = &bearer_req.secInfo; secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; @@ -520,8 +519,9 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t UE->n_initial_pdu = req->nb_of_pdusessions; UE->initial_pdus = calloc(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); AssertFatal(UE->initial_pdus != NULL, "out of memory\n"); - for (int i = 0; i < UE->n_initial_pdu; ++i) - UE->initial_pdus[i] = req->pdusession[i]; + for (int i = 0; i < UE->n_initial_pdu; ++i) { + decodePDUSessionResourceSetup(&UE->initial_pdus[i], &req->pdusession[i]); + } } /* security */ @@ -901,7 +901,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins // At least one because marking one as existing, and setting up another, that // might be more work than is worth it. See 8.2.1.4 in 38.413 for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) { - const pdusession_t *p = &msg->pdusession[i]; + const pdusession_resource_item_t *p = &msg->pdusession[i]; rrc_pdu_session_param_t *exist = find_pduSession(UE, p->pdusession_id, false /* don't create */); if (exist) { LOG_E(NR_RRC, "UE %d: already has existing PDU session %d rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id, p->pdusession_id); @@ -934,7 +934,11 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return; } - if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession, msg->ueAggMaxBitRate.br_dl)) { + pdusession_t to_setup[NGAP_MAX_PDU_SESSION] = {0}; + for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) { + decodePDUSessionResourceSetup(&to_setup[i], &msg->pdusession[i]); + } + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, to_setup, msg->ueAggMaxBitRate.br_dl)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE}; @@ -1062,7 +1066,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins bool all_failed = true; for (int i = 0; i < req->nb_pdusessions_tomodify; i++) { rrc_pdu_session_param_t *sess; - const pdusession_t *sessMod = req->pdusession + i; + const pdusession_resource_item_t *sessMod = req->pdusession + i; for (sess = UE->pduSession; sess < UE->pduSession + UE->nb_of_pdusessions; sess++) if (sess->param.pdusession_id == sessMod->pdusession_id) break; From 48a4c2b0ab5f59e8075ed31f92bf6704b849bc4a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Jun 2025 16:50:22 +0200 Subject: [PATCH 11/18] Move pdu_session_type_t to platform constants * It is used by both NGAP and RRC --- common/5g_platform_types.h | 8 ++++++++ openair2/RRC/NR/nr_rrc_defs.h | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common/5g_platform_types.h b/common/5g_platform_types.h index a5b7b7a1fc..b46490a2e8 100644 --- a/common/5g_platform_types.h +++ b/common/5g_platform_types.h @@ -45,6 +45,14 @@ typedef struct nr_guami_s { uint8_t amf_pointer; } nr_guami_t; +typedef enum { + PDUSessionType_ipv4 = 0, + PDUSessionType_ipv6 = 1, + PDUSessionType_ipv4v6 = 2, + PDUSessionType_ethernet = 3, + PDUSessionType_unstructured = 4 +} pdu_session_type_t; + typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t; #endif diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 89fcfe7561..4f6b941144 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -99,14 +99,6 @@ typedef enum pdu_session_satus_e { PDU_SESSION_STATUS_RELEASED } pdu_session_status_t; -typedef enum pdu_session_type_e { - PDUSessionType_ipv4 = 0, - PDUSessionType_ipv6 = 1, - PDUSessionType_ipv4v6 = 2, - PDUSessionType_ethernet = 3, - PDUSessionType_unstructured = 4 -}pdu_session_type_t; - typedef struct pdusession_s { /* Unique pdusession_id for the UE. */ int pdusession_id; From 0c408875a310803386c7e2d326d9ce7db536a279 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Jun 2025 16:46:27 +0200 Subject: [PATCH 12/18] Refactor NGAP decodePDUSessionResourceSetup/Modify to improve RRC/NGAP separation Motivation of the commit: Previously, the RRC module on the NGAP interface directly handled ASN.1 decoding of NGAP PDU Session Resource items, that was directly stored in pdusession_t, i.e. in the UE context. Decode logic between Setup and Modify was also duplicated., e.g. fill_qos/fill_qos2. The idea behind this change is to achieve this flow: (1) NGAP handler: decoding (2) ITTI to RRC: transfer decoded message (3) RRC handler: process decoded message, e.g. store in UE context, etc.. The goal of this commit is to: * improve the NGAP decoding library by adding decoding functions * let RRC handle the already decoded data * enhance error handling, with decode failures now consistently detected and rejected early * have a cleaner, more maintainable code with fewer duplications and a clearer separation of modules Changes: * Moved all ASN.1 decode logic for PDU Session Resource items into the NGAP library * Introduced decode functions for NGAP IEs whenever necessary, e.g. decode_TNLInformation decode_pdusession_transfer * Removed duplicate fill_qos functions and centralized QoS handling in NGAP * Added function to copy from NGAP PDU Session Resource item to RRC pdusession_t: this actually replaces decodePDUSessionResourceSetup in RRC, copying from the decoded NGAP struct to the UE context pdusession_t --- openair2/COMMON/ngap_messages_types.h | 11 +- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB_NGAP.c | 235 +++----------------------- openair3/NGAP/ngap_gNB_handlers.c | 146 +++++++++++++++- openair3/NGAP/ngap_msg_includes.h | 7 + 5 files changed, 177 insertions(+), 223 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index db7529b797..b5fb021305 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -538,12 +538,21 @@ typedef struct ngap_downlink_nas_s { byte_array_t nas_pdu; } ngap_downlink_nas_t; +/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ +typedef struct { + uint8_t nb_qos; + pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; + pdu_session_type_t pdu_session_type; + // UPF endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_incoming; +} pdusession_transfer_t; + /* PDU Session Resource Setup/Modify Request Item */ typedef struct { int pdusession_id; byte_array_t nas_pdu; nssai_t nssai; - byte_array_t pdusessionTransfer; + pdusession_transfer_t pdusessionTransfer; } pdusession_resource_item_t; typedef struct ngap_initial_context_setup_req_s { diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 4f6b941144..804657e8ce 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -103,7 +103,6 @@ typedef struct pdusession_s { /* Unique pdusession_id for the UE. */ int pdusession_id; byte_array_t nas_pdu; - byte_array_t pdusessionTransfer; uint8_t nb_qos; /* Quality of service for this pdusession */ pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 1bb60df9bc..16df2eac02 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -161,6 +161,20 @@ static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn) return guami; } +/** @brief Copy NGAP PDU Session Resource item to RRC pdusession_t struct */ +static void cp_pdusession_resource_item_to_pdusession(pdusession_t *dst, const pdusession_resource_item_t *src) +{ + dst->pdusession_id = src->pdusession_id; + dst->nas_pdu = src->nas_pdu; + dst->nb_qos = src->pdusessionTransfer.nb_qos; + for (uint8_t i = 0; i < src->pdusessionTransfer.nb_qos && i < QOSFLOW_MAX_VALUE; ++i) { + dst->qos[i] = src->pdusessionTransfer.qos[i]; + } + dst->pdu_session_type = src->pdusessionTransfer.pdu_session_type; + dst->n3_incoming = src->pdusessionTransfer.n3_incoming; + dst->nssai = src->nssai; +} + /** * @brief Prepare the Initial UE Message (Uplink NAS) to be forwarded to the AMF over N2 * extracts NAS PDU, Selected PLMN and Registered AMF from the RRCSetupComplete @@ -225,113 +239,6 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC itti_send_msg_to_task(TASK_NGAP, rrc->module_id, message_p); } -static void fill_qos(NGAP_QosFlowSetupRequestList_t *qos, pdusession_t *session) -{ - DevAssert(qos->list.count > 0); - DevAssert(qos->list.count <= NGAP_maxnoofQosFlows); - for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) { - NGAP_QosFlowSetupRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx]; - // Set the QOS informations - session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; - NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics; - AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx); - if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { - AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = NON_DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI; - } else { - AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI); - } - - ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority; - NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters.allocationAndRetentionPriority; - tmp->priority_level = tmp2->priorityLevelARP; - tmp->pre_emp_capability = tmp2->pre_emptionCapability; - tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability; - } - session->nb_qos = qos->list.count; -} - -static int decodePDUSessionResourceSetup(pdusession_t *out, const pdusession_resource_item_t *session) -{ - NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = NULL; - asn_codec_ctx_t st = {.max_stack_size = 100 * 1000}; - asn_dec_rval_t dec_rval = aper_decode(&st, - &asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, - (void **)&pdusessionTransfer, - session->pdusessionTransfer.buf, - session->pdusessionTransfer.len, - 0, - 0); - - if (dec_rval.code != RC_OK) { - LOG_E(NR_RRC, "can not decode PDUSessionResourceSetupRequestTransfer\n"); - return -1; - } - - for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) { - NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i]; - switch (pdusessionTransfer_ies->id) { - /* optional PDUSessionAggregateMaximumBitRate */ - case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate: - break; - - /* mandatory UL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: { - NGAP_GTPTunnel_t *gTPTunnel_p = pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel; - - /* Set the transport layer address */ - memcpy(out->n3_incoming.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); - out->n3_incoming.addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused; - - /* GTP tunnel endpoint ID */ - OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, out->n3_incoming.teid); - } - - break; - - /* optional AdditionalUL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation: - break; - - /* optional DataForwardingNotPossible */ - case NGAP_ProtocolIE_ID_id_DataForwardingNotPossible: - break; - - /* mandatory PDUSessionType */ - case NGAP_ProtocolIE_ID_id_PDUSessionType: - out->pdu_session_type = (uint8_t)pdusessionTransfer_ies->value.choice.PDUSessionType; - break; - - /* optional SecurityIndication */ - case NGAP_ProtocolIE_ID_id_SecurityIndication: - break; - - /* optional NetworkInstance */ - case NGAP_ProtocolIE_ID_id_NetworkInstance: - break; - - /* mandatory QosFlowSetupRequestList */ - case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: - fill_qos(&pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList, out); - break; - - /* optional CommonNetworkInstance */ - case NGAP_ProtocolIE_ID_id_CommonNetworkInstance: - break; - - default: - LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id); - return -1; - } - } - ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer); - - return 0; -} - /** * @brief Triggers bearer setup for the specified UE. * @@ -363,7 +270,6 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); session->pdu_session_type = sessions[i].pdu_session_type; session->nas_pdu = sessions[i].nas_pdu; - session->pdusessionTransfer = sessions[i].pdusessionTransfer; session->nssai = sessions[i].nssai; bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; security_information_t *secInfo = &bearer_req.secInfo; @@ -519,9 +425,8 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t UE->n_initial_pdu = req->nb_of_pdusessions; UE->initial_pdus = calloc(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); AssertFatal(UE->initial_pdus != NULL, "out of memory\n"); - for (int i = 0; i < UE->n_initial_pdu; ++i) { - decodePDUSessionResourceSetup(&UE->initial_pdus[i], &req->pdusession[i]); - } + for (int i = 0; i < UE->n_initial_pdu; ++i) + cp_pdusession_resource_item_to_pdusession(&UE->initial_pdus[i], &req->pdusession[i]); } /* security */ @@ -935,9 +840,9 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins } pdusession_t to_setup[NGAP_MAX_PDU_SESSION] = {0}; - for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) { - decodePDUSessionResourceSetup(&to_setup[i], &msg->pdusession[i]); - } + for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) + cp_pdusession_resource_item_to_pdusession(&to_setup[i], &msg->pdusession[i]); + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, to_setup, msg->ueAggMaxBitRate.br_dl)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); @@ -949,104 +854,6 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins } } -static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *session) -{ - // we need to duplicate the function fill_qos because all data types are slightly different - DevAssert(qos->list.count > 0); - DevAssert(qos->list.count <= NGAP_maxnoofQosFlows); - for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) { - NGAP_QosFlowAddOrModifyRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx]; - // Set the QOS informations - session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; - NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters->qosCharacteristics; - AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx); - if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { - AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = NON_DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI; - } else { - AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI); - } - - ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority; - NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters->allocationAndRetentionPriority; - tmp->priority_level = tmp2->priorityLevelARP; - tmp->pre_emp_capability = tmp2->pre_emptionCapability; - tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability; - } - session->nb_qos = qos->list.count; -} - -static void decodePDUSessionResourceModify(pdusession_t *param, const byte_array_t pdu) -{ - NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = NULL; - asn_dec_rval_t dec_rval = aper_decode(NULL, - &asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, - (void **)&pdusessionTransfer, - pdu.buf, - pdu.len, - 0, - 0); - - if (dec_rval.code != RC_OK) { - LOG_E(NR_RRC, "could not decode PDUSessionResourceModifyRequestTransfer\n"); - return; - } - - for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) { - NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j]; - switch (pdusessionTransfer_ies->id) { - /* optional PDUSessionAggregateMaximumBitRate */ - case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate\n"); - break; - - /* optional UL-NGU-UP-TNLModifyList */ - case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList\n"); - break; - - /* optional NetworkInstance */ - case NGAP_ProtocolIE_ID_id_NetworkInstance: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_NetworkInstance\n"); - break; - - /* optional QosFlowAddOrModifyRequestList */ - case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList: - fill_qos2(&pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList, param); - break; - - /* optional QosFlowToReleaseList */ - case NGAP_ProtocolIE_ID_id_QosFlowToReleaseList: - // TODO - LOG_E(NR_RRC, "Can't handle NGAP_ProtocolIE_ID_id_QosFlowToReleaseList\n"); - break; - - /* optional AdditionalUL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation\n"); - break; - - /* optional CommonNetworkInstance */ - case NGAP_ProtocolIE_ID_id_CommonNetworkInstance: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_CommonNetworkInstance\n"); - break; - - default: - LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id); - return; - } - } - ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer,pdusessionTransfer ); -} - //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t instance) //------------------------------------------------------------------------------ @@ -1090,8 +897,8 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins if (sessMod->nas_pdu.buf != NULL) { UE->pduSession[i].param.nas_pdu = sessMod->nas_pdu; } - // Save new pdu session parameters, qos, upf addr, teid - decodePDUSessionResourceModify(&sess->param, UE->pduSession[i].param.pdusessionTransfer); + for (int i = 0; i < req->nb_pdusessions_tomodify; ++i) + cp_pdusession_resource_item_to_pdusession(&UE->pduSession[i].param, &req->pdusession[i]); } } diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 6737879e7f..f4c4ebb20f 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -694,6 +694,99 @@ static int ngap_gNB_handle_error_indication(sctp_assoc_t assoc_id, uint32_t stre return 0; } +static void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf) +{ + void *decoded = NULL; + asn_codec_ctx_t ctx = {.max_stack_size = 100 * 1000}; + asn_dec_rval_t rval = aper_decode(&ctx, td, &decoded, buf.buf, buf.size, 0, 0); + if (rval.code != RC_OK) { + NGAP_ERROR("Decoding failed for %s\n", td->name); + return NULL; + } + return decoded; +} + +static pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params) +{ + pdusession_level_qos_parameter_t out = {0}; + // QFI + out.qfi = qfi; + AssertFatal(params != NULL, "QoS parameters are NULL\n"); + // QosCharacteristics + const NGAP_QosCharacteristics_t *qosChar = ¶ms->qosCharacteristics; + AssertFatal(qosChar != NULL, "QoS characteristics are NULL\n"); + if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { + AssertFatal(qosChar->choice.nonDynamic5QI != NULL, "nonDynamic5QI is NULL\n"); + out.fiveQI_type = NON_DYNAMIC; + out.fiveQI = qosChar->choice.nonDynamic5QI->fiveQI; + } else if (qosChar->present == NGAP_QosCharacteristics_PR_dynamic5QI) { + AssertFatal(qosChar->choice.dynamic5QI != NULL, "dynamic5QI is NULL\n"); + out.fiveQI_type = DYNAMIC; + out.fiveQI = *qosChar->choice.dynamic5QI->fiveQI; + } else { + AssertFatal(0, "Unsupported QoS Characteristics present value: %d\n", qosChar->present); + } + // Allocation and Retention Priority + const NGAP_AllocationAndRetentionPriority_t *arp = ¶ms->allocationAndRetentionPriority; + out.allocation_retention_priority.priority_level = arp->priorityLevelARP; + out.allocation_retention_priority.pre_emp_capability = arp->pre_emptionCapability; + out.allocation_retention_priority.pre_emp_vulnerability = arp->pre_emptionVulnerability; + + return out; +} + +static gtpu_tunnel_t decode_TNLInformation(const NGAP_GTPTunnel_t *gTPTunnel_p) +{ + gtpu_tunnel_t out = {0}; + // Transport layer address + memcpy(out.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); + out.addr.length = gTPTunnel_p->transportLayerAddress.size - gTPTunnel_p->transportLayerAddress.bits_unused; + // GTP tunnel endpoint ID + OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, out.teid); + return out; +} + +/** @brief Decode PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ +static bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in) +{ + void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, in); + if (!decoded) { + LOG_E(NR_RRC, "Failed to decode PDUSessionResourceSetupRequestTransfer\n"); + return false; + } + + NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceSetupRequestTransfer_t *)decoded; + for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) { + NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i]; + switch (pdusessionTransfer_ies->id) { + // UL NG-U UP TNL Information (Mandatory) + case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: + out->n3_incoming = decode_TNLInformation(pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel); + break; + + // PDU Session Type (Mandatory) + case NGAP_ProtocolIE_ID_id_PDUSessionType: + out->pdu_session_type = pdusessionTransfer_ies->value.choice.PDUSessionType; + break; + + // QoS Flow Setup Request List (Mandatory) + case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: + out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.count; + for (int i = 0; i < out->nb_qos; i++) { + NGAP_QosFlowSetupRequestItem_t *item = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.array[i]; + out->qos[i] = fill_qos(item->qosFlowIdentifier, &item->qosFlowLevelQosParameters); + } + break; + + default: + LOG_D(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id); + } + } + ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer); + + return true; +} + static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { int i; @@ -767,8 +860,11 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 if (item_p->nAS_PDU) { msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); } - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; - msg->pdusession[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + bool ret = decodePDUSessionResourceSetup(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + if (!ret) { + NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Initial Context Setup Request\n"); + return -1; + } } } @@ -941,11 +1037,14 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 // S-NSSAI msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; msg->pdusession[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); - msg->pdusession[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + bool ret = decodePDUSessionResourceSetup(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + if (!ret) { + NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Setup Request\n"); + return -1; + } } - itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); + itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); return 0; } @@ -1039,6 +1138,37 @@ static int ngap_gNB_handle_paging(sctp_assoc_t assoc_id, uint32_t stream, NGAP_N return 0; } +static bool decodePDUSessionResourceModify(pdusession_transfer_t *out, const OCTET_STRING_t in) +{ + void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, in); + if (!decoded) { + LOG_E(NR_RRC, "Failed to decode PDUSessionResourceModifyRequestTransfer\n"); + return false; + } + + NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceModifyRequestTransfer_t *)decoded; + for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) { + NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j]; + switch (pdusessionTransfer_ies->id) { + /* optional QosFlowAddOrModifyRequestList */ + case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList: + out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.count; + for (int i = 0; i < out->nb_qos; i++) { + NGAP_QosFlowAddOrModifyRequestItem_t *item = + pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.array[i]; + out->qos[i] = fill_qos(item->qosFlowIdentifier, item->qosFlowLevelQosParameters); + } + break; + + default: + LOG_E(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id); + return false; + } + } + ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, pdusessionTransfer); + return true; +} + static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { ngap_gNB_amf_data_t *amf_desc_p = NULL; @@ -1121,8 +1251,10 @@ static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint // check for the NAS PDU if (item_p->nAS_PDU != NULL && item_p->nAS_PDU->size > 0) { msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceModifyRequestTransfer; - msg->pdusession[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + if (!decodePDUSessionResourceModify(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceModifyRequestTransfer)) { + NGAP_ERROR("Failed to decode pDUSessionResourceModifyRequestTransfer\n"); + return -1; + } } else { LOG_W(NGAP, "received pdu session modify with void content for UE %u, pdu session %lu\n", msg->gNB_ue_ngap_id, item_p->pDUSessionID); continue; diff --git a/openair3/NGAP/ngap_msg_includes.h b/openair3/NGAP/ngap_msg_includes.h index c7ef77be6a..1debc2e9f1 100644 --- a/openair3/NGAP/ngap_msg_includes.h +++ b/openair3/NGAP/ngap_msg_includes.h @@ -71,5 +71,12 @@ #include "NGAP_UnsuccessfulOutcome.h" #include "NGAP_UserLocationInformationNR.h" #include "NGAP_asn_constant.h" +#include "NGAP_PDUSessionResourceSetupRequestTransfer.h" +#include "NGAP_QosFlowSetupRequestItem.h" +#include "NGAP_QosCharacteristics.h" +#include "NGAP_NonDynamic5QIDescriptor.h" +#include "NGAP_Dynamic5QIDescriptor.h" +#include "NGAP_PDUSessionResourceModifyRequestTransfer.h" +#include "NGAP_QosFlowAddOrModifyRequestItem.h" #endif // NGAP_MSG_INCLUDES_H From 389b40b121bdaa00df1911ca3a481e714a1164d5 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Jun 2025 16:54:27 +0200 Subject: [PATCH 13/18] Use calloc_or_fail to initiate UE->initial_pdus --- openair2/RRC/NR/rrc_gNB_NGAP.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 16df2eac02..07b969b7f1 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -423,8 +423,7 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t /* if there are PDU sessions to setup, store them to be created once * security (and UE capabilities) are received */ UE->n_initial_pdu = req->nb_of_pdusessions; - UE->initial_pdus = calloc(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); - AssertFatal(UE->initial_pdus != NULL, "out of memory\n"); + UE->initial_pdus = calloc_or_fail(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); for (int i = 0; i < UE->n_initial_pdu; ++i) cp_pdusession_resource_item_to_pdusession(&UE->initial_pdus[i], &req->pdusession[i]); } From e1fc1c38dbbac3bf2a0945db83fb5445f7697690 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 13 May 2025 22:35:18 +0200 Subject: [PATCH 14/18] Use cp_pdusession in trigger_bearer_setup --- openair2/RRC/NR/rrc_gNB_NGAP.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 07b969b7f1..351392de95 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -266,11 +266,8 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession for (int i = 0; i < n; i++) { rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true); pdusession_t *session = &pduSession->param; - session->pdusession_id = sessions[i].pdusession_id; LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); - session->pdu_session_type = sessions[i].pdu_session_type; - session->nas_pdu = sessions[i].nas_pdu; - session->nssai = sessions[i].nssai; + cp_pdusession(session, &sessions[i]); bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; security_information_t *secInfo = &bearer_req.secInfo; secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; From 248cf7f1553e47c9316d338986ded83351f2d2b3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 14 May 2025 11:29:02 +0200 Subject: [PATCH 15/18] Use gtpu_tunnel_t in pdusession_setup_t --- openair2/COMMON/ngap_messages_types.h | 5 ++--- openair2/RRC/NR/rrc_gNB_NGAP.c | 22 +++++++++++++--------- openair3/NGAP/ngap_gNB_nas_procedures.c | 12 ++++++------ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index b5fb021305..2ad2db97bd 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -248,10 +248,9 @@ typedef struct pdusession_setup_s { /* The transport layer address for the IP packets */ uint8_t pdu_session_type; - transport_layer_addr_t gNB_addr; - /* Incoming NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gtp_teid; + // NG-U (N3) Tunnel Endpoint on the RAN side + gtpu_tunnel_t n3_outgoing; /* qos flow list number */ uint8_t nb_of_qos_flow; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 351392de95..9f9a307423 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -467,6 +467,15 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t return 0; } +static gtpu_tunnel_t cp_gtp_tunnel(const gtpu_tunnel_t in) +{ + gtpu_tunnel_t out = {0}; + out.teid = in.teid; + out.addr.length = in.addr.length; + memcpy(out.addr.buffer, in.addr.buffer, out.addr.length); + return out; +} + void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) { MessageDef *msg_p = NULL; @@ -482,11 +491,7 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_ if (session->status == PDU_SESSION_STATUS_DONE) { pdu_sessions_done++; resp->pdusessions[pdusession].pdusession_id = session->param.pdusession_id; - resp->pdusessions[pdusession].gtp_teid = session->param.n3_outgoing.teid; - memcpy(resp->pdusessions[pdusession].gNB_addr.buffer, - session->param.n3_outgoing.addr.buffer, - sizeof(resp->pdusessions[pdusession].gNB_addr.buffer)); - resp->pdusessions[pdusession].gNB_addr.length = 4; // Fixme: IPv4 hard coded here + resp->pdusessions[pdusession].n3_outgoing = cp_gtp_tunnel(session->param.n3_outgoing); resp->pdusessions[pdusession].nb_of_qos_flow = session->param.nb_qos; for (int qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) { resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; @@ -677,10 +682,9 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE pdusession_setup_t *tmp = &resp->pdusessions[pdu_sessions_done]; tmp->pdusession_id = session->param.pdusession_id; tmp->nb_of_qos_flow = session->param.nb_qos; - tmp->gtp_teid = session->param.n3_outgoing.teid; + tmp->n3_outgoing = cp_gtp_tunnel(session->param.n3_outgoing); tmp->pdu_session_type = session->param.pdu_session_type; - tmp->gNB_addr.length = session->param.n3_outgoing.addr.length; - memcpy(tmp->gNB_addr.buffer, session->param.n3_outgoing.addr.buffer, tmp->gNB_addr.length); + for (int qos_flow_index = 0; qos_flow_index < tmp->nb_of_qos_flow; qos_flow_index++) { tmp->associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; tmp->associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; @@ -695,7 +699,7 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE xid, UE->nb_of_pdusessions, tmp->pdusession_id, - tmp->gtp_teid); + tmp->n3_outgoing.teid); pdu_sessions_done++; } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { session->status = PDU_SESSION_STATUS_FAILED; diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 5ae65f1c42..7889d8487c 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -613,8 +613,8 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); - GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].gtp_teid, &tmp->gTP_TEID); - tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); + GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].n3_outgoing.teid, &tmp->gTP_TEID); + tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].n3_outgoing.addr); NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, @@ -623,7 +623,7 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r tmp->transportLayerAddress.buf[2], tmp->transportLayerAddress.buf[3], tmp->transportLayerAddress.size, - initial_ctxt_resp_p->pdusessions[i].gtp_teid); + initial_ctxt_resp_p->pdusessions[i].n3_outgoing.teid); /* associatedQosFlowList. number of 1? */ for(int j=0; j < initial_ctxt_resp_p->pdusessions[i].nb_of_qos_flow; j++) { @@ -928,8 +928,8 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); - GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID); - tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->gNB_addr); + GTP_TEID_TO_ASN1(pdusession->n3_outgoing.teid, &tmp->gTP_TEID); + tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->n3_outgoing.addr); NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, tmp->transportLayerAddress.buf[0], @@ -937,7 +937,7 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re tmp->transportLayerAddress.buf[2], tmp->transportLayerAddress.buf[3], tmp->transportLayerAddress.size, - pdusession->gtp_teid); + pdusession->n3_outgoing.teid); /* associatedQosFlowList. number of 1? */ for(int j=0; j < pdusession_setup_resp_p->pdusessions[i].nb_of_qos_flow; j++) { asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); From b5a717cc995b9a4dce9f46d4317e9aae3468386e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 14 May 2025 13:49:18 +0200 Subject: [PATCH 16/18] Add encoder for PDU Session Resource Setup Response Transfer IE in NGAP (Initial Context/PDU Session) Setup Response --- openair3/NGAP/ngap_gNB_nas_procedures.c | 117 ++++++++++-------------- 1 file changed, 50 insertions(+), 67 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 7889d8487c..1aafeca8c9 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "BIT_STRING.h" #include "INTEGER.h" #include "ngap_msg_includes.h" @@ -57,6 +58,7 @@ #include "oai_asn1.h" #include "s1ap_messages_types.h" #include "xer_encoder.h" +#include "ds/byte_array.h" /** @brief Selects the AMF instance for a given UE based on identity information. * It attempts to select an AMF using the following prioritized criteria: @@ -537,6 +539,46 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance, return 0; } +/** @brief PDU Session Resource Setup Response Transfer encoding (9.3.4.2 3GPP TS 38.413) */ +static byte_array_t encode_ngap_pdusession_setup_response_transfer(const pdusession_setup_t *pdusession) +{ + NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; + byte_array_t out = {0}; + + // DL QoS Flow per TNL Information (Mandatory) + NGAP_QosFlowPerTNLInformation_t *dLQosFlowPerTNLInformation = &pdusessionTransfer.dLQosFlowPerTNLInformation; + + // UP Transport Layer Information (Mandatory) + dLQosFlowPerTNLInformation->uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc(dLQosFlowPerTNLInformation->uPTransportLayerInformation.choice.gTPTunnel, gtp); + GTP_TEID_TO_ASN1(pdusession->n3_outgoing.teid, >p->gTP_TEID); + tnl_to_bitstring(>p->transportLayerAddress, pdusession->n3_outgoing.addr); + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, gtp->transportLayerAddress.buf, ip_str, sizeof(ip_str)); + NGAP_DEBUG("Encoded PDU Session Transfer (%d): TEID=0x%08x, Addr=%s\n", + pdusession->pdusession_id, + pdusession->n3_outgoing.teid, + ip_str); + + // Associated QoS Flow List (Mandatory) + for (int j = 0; j < pdusession->nb_of_qos_flow; j++) { + asn1cSequenceAdd(dLQosFlowPerTNLInformation->associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, qos_item); + // QoS Flow Identifier (Mandatory) + qos_item->qosFlowIdentifier = pdusession->associated_qos_flows[j].qfi; + } + + // Encode + asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, + ATS_ALIGNED_CANONICAL_PER, + &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, + &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_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + out.buf = res.buffer; + out.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) //------------------------------------------------------------------------------ @@ -606,39 +648,10 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r asn1cSequenceAdd(ie->value.choice.PDUSessionResourceSetupListCxtRes.list, NGAP_PDUSessionResourceSetupItemCxtRes_t, item); /* pDUSessionID */ item->pDUSessionID = initial_ctxt_resp_p->pdusessions[i].pdusession_id; - - /* dLQosFlowPerTNLInformation */ - NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; - - pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; - - asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); - GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].n3_outgoing.teid, &tmp->gTP_TEID); - tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].n3_outgoing.addr); - - NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", - item->pDUSessionID, - tmp->transportLayerAddress.buf[0], - tmp->transportLayerAddress.buf[1], - tmp->transportLayerAddress.buf[2], - tmp->transportLayerAddress.buf[3], - tmp->transportLayerAddress.size, - initial_ctxt_resp_p->pdusessions[i].n3_outgoing.teid); - - /* associatedQosFlowList. number of 1? */ - for(int j=0; j < initial_ctxt_resp_p->pdusessions[i].nb_of_qos_flow; j++) { - asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); - /* qosFlowIdentifier */ - ass_qos_item_p->qosFlowIdentifier = initial_ctxt_resp_p->pdusessions[i].associated_qos_flows[j].qfi; - } - - void *pdusessionTransfer_buffer; - ssize_t encoded = aper_encode_to_new_buffer(&asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, NULL, &pdusessionTransfer, &pdusessionTransfer_buffer); - AssertFatal(encoded > 0, "ASN1 message encoding failed !\n"); - item->pDUSessionResourceSetupResponseTransfer.buf = pdusessionTransfer_buffer; - item->pDUSessionResourceSetupResponseTransfer.size = encoded; - - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + // PDU Session Resource Setup Response Transfer (Mandatory) + byte_array_t ba = encode_ngap_pdusession_setup_response_transfer(&initial_ctxt_resp_p->pdusessions[i]); + item->pDUSessionResourceSetupResponseTransfer.buf = ba.buf; + item->pDUSessionResourceSetupResponseTransfer.size = ba.len; } } /* optional */ @@ -924,40 +937,10 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re /* pDUSessionID */ item->pDUSessionID = pdusession->pdusession_id; - /* dLQosFlowPerTNLInformation */ - NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; - pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); - GTP_TEID_TO_ASN1(pdusession->n3_outgoing.teid, &tmp->gTP_TEID); - tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->n3_outgoing.addr); - NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", - item->pDUSessionID, - tmp->transportLayerAddress.buf[0], - tmp->transportLayerAddress.buf[1], - tmp->transportLayerAddress.buf[2], - tmp->transportLayerAddress.buf[3], - tmp->transportLayerAddress.size, - pdusession->n3_outgoing.teid); - /* associatedQosFlowList. number of 1? */ - for(int j=0; j < pdusession_setup_resp_p->pdusessions[i].nb_of_qos_flow; j++) { - asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); - - /* qosFlowIdentifier */ - ass_qos_item_p->qosFlowIdentifier = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qfi; - - /* qosFlowMappingIndication */ - // if(pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind != QOSFLOW_MAPPING_INDICATION_NON) { - // ass_qos_item_p->qosFlowMappingIndication = malloc(sizeof(*ass_qos_item_p->qosFlowMappingIndication)); - // *ass_qos_item_p->qosFlowMappingIndication = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind; - // } - } - - asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); - AssertFatal (res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); - item->pDUSessionResourceSetupResponseTransfer.buf = res.buffer; - item->pDUSessionResourceSetupResponseTransfer.size = res.result.encoded; - - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + // PDU Session Resource Setup Response Transfer (Mandatory) + byte_array_t ba = encode_ngap_pdusession_setup_response_transfer(pdusession); + item->pDUSessionResourceSetupResponseTransfer.buf = ba.buf; + item->pDUSessionResourceSetupResponseTransfer.size = ba.len; } } From 7d0640ebcb391bee034737d8d204cfbfa5a9e026 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 14 May 2025 16:52:43 +0200 Subject: [PATCH 17/18] Improve PDU Session GTP tunnels logging --- openair2/RRC/NR/rrc_gNB_NGAP.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 9f9a307423..72aad97750 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "E1AP_ConfidentialityProtectionIndication.h" #include "E1AP_IntegrityProtectionIndication.h" #include "NGAP_CauseRadioNetwork.h" @@ -266,7 +267,6 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession for (int i = 0; i < n; i++) { rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true); pdusession_t *session = &pduSession->param; - LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); cp_pdusession(session, &sessions[i]); bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; security_information_t *secInfo = &bearer_req.secInfo; @@ -287,8 +287,12 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession : SECURITY_NOT_NEEDED; sec->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? SECURITY_REQUIRED : SECURITY_NOT_NEEDED; - pdu->UP_TL_information.teId = session->n3_incoming.teid; - memcpy(&pdu->UP_TL_information.tlAddress, session->n3_incoming.addr.buffer, sizeof(in_addr_t)); + gtpu_tunnel_t *n3_incoming = &session->n3_incoming; + pdu->UP_TL_information.teId = n3_incoming->teid; + memcpy(&pdu->UP_TL_information.tlAddress, n3_incoming->addr.buffer, sizeof(in_addr_t)); + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, n3_incoming->addr.buffer, ip_str, sizeof(ip_str)); + LOG_I(NR_RRC, "Bearer Context Setup: PDU Session ID=%d, incoming TEID=0x%08x, Addr=%s\n", session->pdusession_id, n3_incoming->teid, ip_str); /* we assume for the moment one DRB per PDU session. Activate the bearer, * and configure in RRC. */ @@ -691,15 +695,9 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE } session->status = PDU_SESSION_STATUS_ESTABLISHED; - LOG_I(NR_RRC, - "msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d, pdusession_id %d, teid: %u \n ", - pdu_sessions_done, - pdusession, - session->status, - xid, - UE->nb_of_pdusessions, - tmp->pdusession_id, - tmp->n3_outgoing.teid); + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, tmp->n3_outgoing.addr.buffer, ip_str, sizeof(ip_str)); + LOG_I(NR_RRC, "PDU Session Setup Response: ID=%d, outgoing TEID=0x%08x, Addr=%s\n", tmp->pdusession_id, tmp->n3_outgoing.teid, ip_str); pdu_sessions_done++; } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { session->status = PDU_SESSION_STATUS_FAILED; From 122ff99b49fcac20a6eb4ecafbca9ece61e7d2d1 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Jun 2025 13:12:26 +0200 Subject: [PATCH 18/18] Use f1u_gtp_update in rrc_gNB_process_e1_bearer_context_setup_resp --- openair2/RRC/NR/rrc_gNB.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index cda981ee34..e5513fdbdc 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2449,9 +2449,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id); continue; } - rrc_pdu->param.n3_outgoing.teid = e1_pdu->tl_info.teId; - memcpy(&rrc_pdu->param.n3_outgoing.addr.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4); - rrc_pdu->param.n3_outgoing.addr.length = sizeof(in_addr_t); + rrc_pdu->param.n3_outgoing = f1u_gtp_update(e1_pdu->tl_info.teId, e1_pdu->tl_info.tlAddress); // save the tunnel address for the DRBs for (int i = 0; i < e1_pdu->numDRBSetup; i++) {