From 002fa0050f767552ff22522a40716502c5b61d89 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 10 Mar 2025 18:15:34 +0100 Subject: [PATCH 1/8] Bugfix in ngap_gNB_handle_ng_setup_response: use correct count for PLMNSupportList --- openair3/NGAP/ngap_gNB_handlers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 97f15ef658..c692731e3e 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -251,7 +251,7 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str STAILQ_INIT(&amf_desc_p->plmn_supports); - for (i = 0; i < ie->value.choice.ServedGUAMIList.list.count; i++) { + for (i = 0; i < ie->value.choice.PLMNSupportList.list.count; i++) { NGAP_PLMNSupportItem_t *plmn_support_item_p; struct plmn_support_s *new_plmn_support_p; NGAP_SliceSupportItem_t *slice_support_item_p; From 4c179270c26b63f1bd92d413e0d863089bac65c3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 24 Sep 2024 11:52:59 +0200 Subject: [PATCH 2/8] Add guami_t to ngran_types.h * refactor NGAP and RRC code to use one common GUAMI type instead of two identical ones --- common/5g_platform_types.h | 10 ++++++++++ openair2/COMMON/ngap_messages_types.h | 15 +++------------ openair2/RRC/NR/nr_rrc_defs.h | 12 ++---------- openair2/RRC/NR/rrc_gNB_NGAP.c | 10 ++-------- openair3/NGAP/ngap_gNB_nnsf.c | 12 ++++-------- openair3/NGAP/ngap_gNB_nnsf.h | 11 ++++------- 6 files changed, 25 insertions(+), 45 deletions(-) diff --git a/common/5g_platform_types.h b/common/5g_platform_types.h index 6f055e9305..a5b7b7a1fc 100644 --- a/common/5g_platform_types.h +++ b/common/5g_platform_types.h @@ -35,6 +35,16 @@ typedef struct nssai_s { uint32_t sd; } nssai_t; +// Globally Unique AMF Identifier +typedef struct nr_guami_s { + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_len; + uint8_t amf_region_id; + uint16_t amf_set_id; + uint8_t amf_pointer; +} nr_guami_t; + typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t; #endif diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 588d7c5cba..6d4998fede 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -199,15 +199,6 @@ typedef struct pdusession_level_qos_parameter_s { ngap_allocation_retention_priority_t allocation_retention_priority; } pdusession_level_qos_parameter_t; -typedef struct ngap_guami_s { - uint16_t mcc; - uint16_t mnc; - uint8_t mnc_len; - uint8_t amf_region_id; - uint16_t amf_set_id; - uint8_t amf_pointer; -} ngap_guami_t; - typedef struct fiveg_s_tmsi_s { uint16_t amf_set_id; uint8_t amf_pointer; @@ -233,7 +224,7 @@ typedef enum ngap_ue_identities_presenceMask_e { typedef struct ngap_ue_identity_s { ngap_ue_identities_presenceMask_t presenceMask; fiveg_s_tmsi_t s_tmsi; - ngap_guami_t guami; + nr_guami_t guami; } ngap_ue_identity_t; typedef struct ngap_nas_pdu_s { @@ -613,7 +604,7 @@ typedef struct ngap_initial_context_setup_req_s { ngap_ambr_t ue_ambr; /* guami */ - ngap_guami_t guami; + nr_guami_t guami; /* allowed nssai */ uint8_t nb_allowed_nssais; @@ -719,7 +710,7 @@ typedef struct ngap_path_switch_req_s { /* AMF UE id */ uint64_t amf_ue_ngap_id; - ngap_guami_t ue_guami; + nr_guami_t ue_guami; uint16_t ue_initial_id; /* Security algorithms */ diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 79d102f9e3..32892d6e6f 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -86,15 +86,6 @@ typedef struct nr_e_rab_param_s { uint8_t xid; // transaction_id } __attribute__ ((__packed__)) nr_e_rab_param_t; -typedef struct nr_rrc_guami_s { - uint16_t mcc; - uint16_t mnc; - uint8_t mnc_len; - uint8_t amf_region_id; - uint16_t amf_set_id; - uint8_t amf_pointer; -} nr_rrc_guami_t; - typedef enum pdu_session_satus_e { PDU_SESSION_STATUS_NEW, PDU_SESSION_STATUS_DONE, @@ -217,7 +208,8 @@ typedef struct gNB_RRC_UE_s { uint64_t nr_cellid; uint32_t rrc_ue_id; uint64_t amf_ue_ngap_id; - nr_rrc_guami_t ue_guami; + // Globally Unique AMF Identifier + nr_guami_t ue_guami; ngap_security_capabilities_t security_capabilities; //NSA block diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index fadbea4825..761db394ae 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -491,14 +491,8 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t UE->amf_ue_ngap_id = req->amf_ue_ngap_id; - /* store guami in gNB_RRC_UE_t context; - * we copy individual members because the guami types are different (nr_rrc_guami_t and ngap_guami_t) */ - UE->ue_guami.mcc = req->guami.mcc; - UE->ue_guami.mnc = req->guami.mnc; - UE->ue_guami.mnc_len = req->guami.mnc_len; - UE->ue_guami.amf_region_id = req->guami.amf_region_id; - UE->ue_guami.amf_set_id = req->guami.amf_set_id; - UE->ue_guami.amf_pointer = req->guami.amf_pointer; + // Directly copy the entire guami structure + UE->ue_guami = req->guami; /* NAS PDU */ // this is malloced pointers, we pass it for later free() diff --git a/openair3/NGAP/ngap_gNB_nnsf.c b/openair3/NGAP/ngap_gNB_nnsf.c index e9f23c6401..54c8a505bb 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.c +++ b/openair3/NGAP/ngap_gNB_nnsf.c @@ -234,10 +234,9 @@ ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, return NULL; } -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - ngap_guami_t guami) +struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, + ngap_rrc_establishment_cause_t cause, + nr_guami_t guami) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; @@ -327,10 +326,7 @@ ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, return NULL; } - -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, - ngap_guami_t guami) +struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, nr_guami_t guami) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL; diff --git a/openair3/NGAP/ngap_gNB_nnsf.h b/openair3/NGAP/ngap_gNB_nnsf.h index bf6c309af0..8b20b0cad4 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.h +++ b/openair3/NGAP/ngap_gNB_nnsf.h @@ -49,13 +49,10 @@ ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, int selected_plmn_identity, uint8_t amf_setid); -struct ngap_gNB_amf_data_s* -ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - ngap_guami_t guami); +struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, + ngap_rrc_establishment_cause_t cause, + nr_guami_t guami); -struct ngap_gNB_amf_data_s* -ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, - ngap_guami_t guami); +struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, nr_guami_t guami); #endif /* NGAP_GNB_NNSF_H_ */ From 8fb8713023ff110355cf38d7811b7f17208dc33a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 10 Mar 2025 18:50:08 +0100 Subject: [PATCH 3/8] Replace ngap_pdu_t with byte_array_t ngap_pdu_t has the same definition as byte_array_t, so it is replaced by the latter. This simplify the stack and reduces duplicated code. Also, add function create_byte_array to copy from an existing buffer to a new byte_array_t and replaced allocCopy with create_byte_array, and adopted OCTET_STRING_fromBuf whenever possible. --- common/utils/ds/byte_array.c | 18 ++-- common/utils/ds/byte_array.h | 8 ++ openair2/COMMON/ngap_messages_types.h | 32 +++---- openair2/RRC/NR/nr_rrc_defs.h | 2 +- openair2/RRC/NR/rrc_gNB.c | 87 ++++++++----------- openair2/RRC/NR/rrc_gNB_NGAP.c | 42 +++++---- openair3/NGAP/ngap_gNB_handlers.c | 34 +++----- openair3/NGAP/ngap_gNB_itti_messaging.c | 4 +- .../NGAP/ngap_gNB_management_procedures.c | 1 + .../NGAP/ngap_gNB_management_procedures.h | 2 + openair3/NGAP/ngap_gNB_nas_procedures.c | 28 +++--- 11 files changed, 121 insertions(+), 137 deletions(-) diff --git a/common/utils/ds/byte_array.c b/common/utils/ds/byte_array.c index d6ad97e324..99375bf2aa 100644 --- a/common/utils/ds/byte_array.c +++ b/common/utils/ds/byte_array.c @@ -23,15 +23,21 @@ #include #include +#include "common/utils/utils.h" // for malloc_or_fail + +byte_array_t create_byte_array(const size_t len, const uint8_t* buffer) +{ + byte_array_t result = {.len = len}; + if (len) { + result.buf = malloc_or_fail(len); + memcpy(result.buf, buffer, len); + } + return result; +} byte_array_t copy_byte_array(byte_array_t src) { - byte_array_t dst = {0}; - dst.buf = malloc(src.len); - assert(dst.buf != NULL && "Memory exhausted"); - memcpy(dst.buf, src.buf, src.len); - dst.len = src.len; - return dst; + return create_byte_array(src.len, src.buf); } void free_byte_array(byte_array_t ba) diff --git a/common/utils/ds/byte_array.h b/common/utils/ds/byte_array.h index 18adb33047..e303d38e75 100644 --- a/common/utils/ds/byte_array.h +++ b/common/utils/ds/byte_array.h @@ -28,6 +28,13 @@ #include #include +#define FREE_AND_ZERO_BYTE_ARRAY(BA) \ + do { \ + free_byte_array(BA); \ + BA.buf = NULL; \ + BA.len = 0; \ + } while (0) + typedef struct { size_t len; uint8_t* buf; @@ -43,5 +50,6 @@ bool eq_byte_array(const byte_array_t* m0, const byte_array_t* m1); byte_array_t cp_str_to_ba(const char* str); char* cp_ba_to_str(const byte_array_t ba); +byte_array_t create_byte_array(const size_t len, const uint8_t* buffer); #endif diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 6d4998fede..f833fbdbf0 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -34,6 +34,7 @@ #include "common/platform_types.h" #include "common/5g_platform_types.h" #include "s1ap_messages_types.h" +#include "ds/byte_array.h" // Defines to access message fields. #define NGAP_REGISTER_GNB_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_register_gnb_req @@ -227,13 +228,6 @@ typedef struct ngap_ue_identity_s { nr_guami_t guami; } ngap_ue_identity_t; -typedef struct ngap_nas_pdu_s { - /* Octet string data */ - uint8_t *buffer; - /* Length of the octet string */ - uint32_t length; -} ngap_pdu_t; - typedef struct ngap_mobility_restriction_s{ ngap_plmn_identity_t serving_plmn; }ngap_mobility_restriction_t; @@ -249,8 +243,8 @@ typedef enum pdu_session_type_e { typedef struct pdusession_s { /* Unique pdusession_id for the UE. */ int pdusession_id; - ngap_pdu_t nas_pdu; - ngap_pdu_t pdusessionTransfer; + 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]; @@ -508,7 +502,7 @@ typedef struct ngap_nas_first_req_s { ngap_rrc_establishment_cause_t establishment_cause; /* NAS PDU */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; /* If this flag is set NGAP layer is expecting the GUAMI. If = 0, * the temporary s-tmsi is used. @@ -520,12 +514,12 @@ typedef struct ngap_uplink_nas_s { /* Unique UE identifier within an gNB */ uint32_t gNB_ue_ngap_id; /* NAS pdu */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; } ngap_uplink_nas_t; typedef struct ngap_ue_cap_info_ind_s { uint32_t gNB_ue_ngap_id; - ngap_pdu_t ue_radio_cap; + byte_array_t ue_radio_cap; } ngap_ue_cap_info_ind_t; typedef struct ngap_initial_context_setup_resp_s { @@ -552,7 +546,7 @@ typedef struct ngap_initial_context_setup_fail_s { typedef struct ngap_nas_non_delivery_ind_s { uint32_t gNB_ue_ngap_id; - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; /* TODO: add cause */ } ngap_nas_non_delivery_ind_t; @@ -590,7 +584,7 @@ typedef struct ngap_downlink_nas_s { /* UE id for initial connection to NGAP */ uint32_t gNB_ue_ngap_id; /* NAS pdu */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; } ngap_downlink_nas_t; @@ -627,7 +621,7 @@ typedef struct ngap_initial_context_setup_req_s { /* Nas Pdu */ uint8_t nas_pdu_flag; - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; } ngap_initial_context_setup_req_t; @@ -656,8 +650,8 @@ typedef struct ngap_paging_ind_s { typedef struct { /* Unique pdusession_id for the UE. */ int pdusession_id; - ngap_pdu_t nas_pdu; - ngap_pdu_t pdusessionTransfer; + byte_array_t nas_pdu; + byte_array_t pdusessionTransfer; } pdusession_setup_req_t; typedef struct ngap_pdusession_setup_req_s { @@ -783,7 +777,7 @@ typedef struct ngap_ue_release_command_s { typedef struct pdusession_release_s { /* Unique pdusession_id for the UE. */ uint8_t pdusession_id; - ngap_pdu_t data; + byte_array_t data; } pdusession_release_t; typedef struct ngap_ue_release_req_s { @@ -831,7 +825,7 @@ typedef struct ngap_pdusession_release_command_s { uint32_t gNB_ue_ngap_id; /* The NAS PDU should be forwarded by the RRC layer to the NAS layer */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; /* Number of pdusession to be released in the list */ uint8_t nb_pdusessions_torelease; diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 32892d6e6f..2a36b8013e 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -239,7 +239,7 @@ typedef struct gNB_RRC_UE_s { pdusession_t *initial_pdus; /* Nas Pdu */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; /* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */ int max_delays_pdu_session; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a110e4af53..a9ef3d9028 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -95,6 +95,7 @@ #include "E1AP/lib/e1ap_bearer_context_management.h" #include "E1AP/lib/e1ap_interface_management.h" #include "NR_DL-DCCH-Message.h" +#include "ds/byte_array.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -123,17 +124,6 @@ static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_i data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd); } -///---------------------------------------------------------------------------------------------------------------/// -///---------------------------------------------------------------------------------------------------------------/// - -static void clear_nas_pdu(ngap_pdu_t *pdu) -{ - DevAssert(pdu != NULL); - free(pdu->buffer); // does nothing if NULL - pdu->buffer = NULL; - pdu->length = 0; -} - static void freeDRBlist(NR_DRB_ToAddModList_t *list) { //ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); @@ -675,13 +665,11 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { + if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, - (char *)ue_p->pduSession[i].param.nas_pdu.buffer, - ue_p->pduSession[i].param.nas_pdu.length); + OCTET_STRING_fromBuf(msg, (char *)ue_p->pduSession[i].param.nas_pdu.buf, ue_p->pduSession[i].param.nas_pdu.len); - LOG_D(NR_RRC, "add NAS info with size %d (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.length, i); + LOG_D(NR_RRC, "add NAS info with size %ld (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.len, i); ue_p->pduSession[i].xid = xid; } if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { @@ -689,9 +677,9 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ } } - if (ue_p->nas_pdu.length) { + if (ue_p->nas_pdu.len) { asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buffer, ue_p->nas_pdu.length); + OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buf, ue_p->nas_pdu.len); } /* If list is empty free the list and reset the address */ @@ -702,7 +690,7 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ /* Free all NAS PDUs */ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); + FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; // TODO refactor dedicatedNAS_MessageList @@ -724,16 +712,17 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t CALLOC(1, sizeof(*dedicatedNAS_MessageList)); for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { + rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; // bypass the new and already configured pdu sessions - if (ue_p->pduSession[i].status >= PDU_SESSION_STATUS_DONE) { - ue_p->pduSession[i].xid = xid; + if (session->status >= PDU_SESSION_STATUS_DONE) { + session->xid = xid; continue; } - if (ue_p->pduSession[i].cause.type != NGAP_CAUSE_NOTHING) { + if (session->cause.type != NGAP_CAUSE_NOTHING) { // set xid of failure pdu session - ue_p->pduSession[i].xid = xid; - ue_p->pduSession[i].status = PDU_SESSION_STATUS_FAILED; + session->xid = xid; + session->status = PDU_SESSION_STATUS_FAILED; continue; } @@ -741,21 +730,21 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t int j; for (j = 0; i < MAX_DRBS_PER_UE; j++) { if (ue_p->established_drbs[j].status != DRB_INACTIVE - && ue_p->established_drbs[j].cnAssociation.sdap_config.pdusession_id == ue_p->pduSession[i].param.pdusession_id) + && ue_p->established_drbs[j].cnAssociation.sdap_config.pdusession_id == session->param.pdusession_id) break; } if (j == MAX_DRBS_PER_UE) { ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_unspecified}; - ue_p->pduSession[i].xid = xid; - ue_p->pduSession[i].status = PDU_SESSION_STATUS_FAILED; - ue_p->pduSession[i].cause = cause; + session->xid = xid; + session->status = PDU_SESSION_STATUS_FAILED; + session->cause = cause; continue; } // Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping - for (qos_flow_index = 0; qos_flow_index < ue_p->pduSession[i].param.nb_qos; qos_flow_index++) { - switch (ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI) { + for (qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) { + switch (session->param.qos[qos_flow_index].fiveQI) { case 1: //100ms case 2: //150ms case 3: //50ms @@ -769,27 +758,23 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t break; default: - LOG_E(NR_RRC, "not supported 5qi %lu\n", ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI); + LOG_E(NR_RRC, "not supported 5qi %lu\n", session->param.qos[qos_flow_index].fiveQI); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_not_supported_5QI_value}; - ue_p->pduSession[i].status = PDU_SESSION_STATUS_FAILED; - ue_p->pduSession[i].xid = xid; - ue_p->pduSession[i].cause = cause; + session->status = PDU_SESSION_STATUS_FAILED; + session->xid = xid; + session->cause = cause; continue; } - LOG_I(NR_RRC, - "index %d, QOS flow %d, 5QI %ld \n", - i, - qos_flow_index, - ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI); + LOG_I(NR_RRC, "index %d, QOS flow %d, 5QI %ld \n", i, qos_flow_index, session->param.qos[qos_flow_index].fiveQI); } - ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; - ue_p->pduSession[i].xid = xid; + session->status = PDU_SESSION_STATUS_DONE; + session->xid = xid; - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { + if (session->param.nas_pdu.buf != NULL) { asn1cSequenceAdd(dedicatedNAS_MessageList->list,NR_DedicatedNAS_Message_t, dedicatedNAS_Message); - OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)ue_p->pduSession[i].param.nas_pdu.buffer, ue_p->pduSession[i].param.nas_pdu.length); - LOG_I(NR_RRC, "add NAS info with size %d (pdusession id %d)\n", ue_p->pduSession[i].param.nas_pdu.length, ue_p->pduSession[i].param.pdusession_id); + OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)session->param.nas_pdu.buf, session->param.nas_pdu.len); + LOG_I(NR_RRC, "add NAS info with size %ld (pdusession id %d)\n", session->param.nas_pdu.len, session->param.pdusession_id); } } @@ -817,7 +802,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t /* Free all NAS PDUs */ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); + FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d)\n", ue_p->rrc_ue_id, size); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; @@ -1596,21 +1581,21 @@ static int handle_rrcReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE */ void rrc_forward_ue_nas_message(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) { - if (UE->nas_pdu.buffer == NULL || UE->nas_pdu.length == 0) + if (UE->nas_pdu.buf == NULL || UE->nas_pdu.len == 0) return; // no problem: the UE will re-request a NAS PDU - LOG_UE_DL_EVENT(UE, "Send DL Information Transfer [%d bytes]\n", UE->nas_pdu.length); + LOG_UE_DL_EVENT(UE, "Send DL Information Transfer [%ld bytes]\n", UE->nas_pdu.len); uint8_t buffer[4096]; unsigned int xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - uint32_t length = do_NR_DLInformationTransfer(buffer, sizeof(buffer), xid, UE->nas_pdu.length, UE->nas_pdu.buffer); + uint32_t length = do_NR_DLInformationTransfer(buffer, sizeof(buffer), xid, UE->nas_pdu.len, UE->nas_pdu.buf); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, buffer, length, "[MSG] RRC DL Information Transfer\n"); rb_id_t srb_id = UE->Srb[2].Active ? DL_SCH_LCID_DCCH1 : DL_SCH_LCID_DCCH; const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_dlInformationTransfer; nr_rrc_transfer_protected_rrc_message(rrc, UE, srb_id, msg_id, buffer, length); - // no need to free UE->nas_pdu.buffer, do_NR_DLInformationTransfer() did that - UE->nas_pdu.buffer = NULL; - UE->nas_pdu.length = 0; + // no need to free UE->nas_pdu.buf, do_NR_DLInformationTransfer() did that + UE->nas_pdu.buf = NULL; + UE->nas_pdu.len = 0; } static void handle_ueCapabilityInformation(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_UECapabilityInformation_t *ue_cap_info) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 761db394ae..85d9cffeb3 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -166,13 +166,7 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC req->establishment_cause = UE->establishment_cause; /* Forward NAS message */ - req->nas_pdu.length = rrcSetupComplete->dedicatedNAS_Message.size; - req->nas_pdu.buffer = malloc(req->nas_pdu.length); - AssertFatal(req->nas_pdu.buffer != NULL, "out of memory\n"); - memcpy(req->nas_pdu.buffer, rrcSetupComplete->dedicatedNAS_Message.buf, req->nas_pdu.length); - // extract_imsi(NGAP_NAS_FIRST_REQ (message_p).nas_pdu.buffer, - // NGAP_NAS_FIRST_REQ (message_p).nas_pdu.length, - // ue_context_pP); + req->nas_pdu = create_byte_array(rrcSetupComplete->dedicatedNAS_Message.size, rrcSetupComplete->dedicatedNAS_Message.buf); /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */ int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; @@ -247,8 +241,13 @@ static int decodePDUSessionResourceSetup(pdusession_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.buffer, session->pdusessionTransfer.length, 0, 0); + 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"); @@ -707,8 +706,7 @@ int rrc_gNB_process_NGAP_DOWNLINK_NAS(MessageDef *msg_p, instance_t instance, mu msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_NAS_NON_DELIVERY_IND); ngap_nas_non_delivery_ind_t *msg = &NGAP_NAS_NON_DELIVERY_IND(msg_fail_p); msg->gNB_ue_ngap_id = req->gNB_ue_ngap_id; - msg->nas_pdu.length = req->nas_pdu.length; - msg->nas_pdu.buffer = req->nas_pdu.buffer; + msg->nas_pdu = req->nas_pdu; // TODO add failure cause when defined! itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p); return (-1); @@ -740,8 +738,8 @@ void rrc_gNB_send_NGAP_UPLINK_NAS(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_ memcpy(buf, nas->buf, nas->size); MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, rrc->module_id, NGAP_UPLINK_NAS); NGAP_UPLINK_NAS(msg_p).gNB_ue_ngap_id = UE->rrc_ue_id; - NGAP_UPLINK_NAS(msg_p).nas_pdu.length = nas->size; - NGAP_UPLINK_NAS(msg_p).nas_pdu.buffer = buf; + NGAP_UPLINK_NAS(msg_p).nas_pdu.len = nas->size; + NGAP_UPLINK_NAS(msg_p).nas_pdu.buf = buf; itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); } @@ -966,10 +964,16 @@ static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *s session->nb_qos = qos->list.count; } -static void decodePDUSessionResourceModify(pdusession_t *param, const ngap_pdu_t pdu) +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.buffer, pdu.length, 0, 0); + 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"); @@ -1068,7 +1072,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins sess->status = PDU_SESSION_STATUS_NEW; sess->param.pdusession_id = sessMod->pdusession_id; sess->cause.type = NGAP_CAUSE_NOTHING; - if (sessMod->nas_pdu.buffer != NULL) { + if (sessMod->nas_pdu.buf != NULL) { UE->pduSession[i].param.nas_pdu = sessMod->nas_pdu; } // Save new pdu session parameters, qos, upf addr, teid @@ -1339,8 +1343,8 @@ void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, ngap_ue_cap_info_ind_t *ind = &NGAP_UE_CAPABILITIES_IND(msg_p); memset(ind, 0, sizeof(*ind)); ind->gNB_ue_ngap_id = UE->rrc_ue_id; - ind->ue_radio_cap.length = encoded; - ind->ue_radio_cap.buffer = buf2; + ind->ue_radio_cap.len = encoded; + ind->ue_radio_cap.buf = buf2; itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p); LOG_I(NR_RRC,"Send message to ngap: NGAP_UE_CAPABILITIES_IND\n"); } @@ -1419,7 +1423,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ if (found) { // TODO RRCReconfiguration To UE LOG_I(NR_RRC, "Send RRCReconfiguration To UE \n"); - rrc_gNB_generate_dedicatedRRCReconfiguration_release(rrc, UE, xid, cmd->nas_pdu.length, cmd->nas_pdu.buffer); + rrc_gNB_generate_dedicatedRRCReconfiguration_release(rrc, UE, xid, cmd->nas_pdu.len, cmd->nas_pdu.buf); } else { // gtp tunnel delete LOG_I(NR_RRC, "gtp tunnel delete all tunnels for UE %04x\n", UE->rnti); diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index c692731e3e..a93ad76ed7 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -52,15 +52,6 @@ #include "oai_asn1.h" #include "queue.h" -static void allocCopy(ngap_pdu_t *out, OCTET_STRING_t in) -{ - if (in.size) { - out->buffer = malloc(in.size); - memcpy(out->buffer, in.buf, in.size); - } - out->length = in.size; -} - char *ngap_direction2String(int ngap_dir) { static char *ngap_direction_String[] = { "", /* Nothing */ @@ -772,9 +763,10 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 } if (item_p->nAS_PDU) { - allocCopy(&msg->pdusession_param[i].nas_pdu, *item_p->nAS_PDU); + msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); } - allocCopy(&msg->pdusession_param[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; + msg->pdusession_param[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } } @@ -841,7 +833,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 NGAP_ProtocolIE_ID_id_NAS_PDU, false); if (ie) - allocCopy(&msg->nas_pdu, ie->value.choice.NAS_PDU); + msg->nas_pdu = create_byte_array(ie->value.choice.NAS_PDU.size, ie->value.choice.NAS_PDU.buf); itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); @@ -985,9 +977,9 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 } else { msg->pdusession_setup_params[i].nssai.sd = 0xffffff; } - - allocCopy(&msg->pdusession_setup_params[i].nas_pdu, *item_p->pDUSessionNAS_PDU); - allocCopy(&msg->pdusession_setup_params[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + 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); } itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); @@ -1164,8 +1156,9 @@ 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) { - allocCopy(&msg->pdusession_modify_params[i].nas_pdu, *item_p->nAS_PDU); - allocCopy(&msg->pdusession_modify_params[i].pdusessionTransfer, item_p->pDUSessionResourceModifyRequestTransfer); + msg->pdusession_modify_params[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); } 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; @@ -1241,7 +1234,7 @@ static int ngap_gNB_handle_pdusession_release_command(sctp_assoc_t assoc_id, uin NGAP_ProtocolIE_ID_id_NAS_PDU, false); if (ie) - allocCopy(&msg->nas_pdu, ie->value.choice.NAS_PDU); + msg->nas_pdu = create_byte_array(ie->value.choice.NAS_PDU.size, ie->value.choice.NAS_PDU.buf); /* id-PDUSessionResourceToReleaseListRelCmd */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceReleaseCommandIEs_t, ie, container, @@ -1252,8 +1245,9 @@ static int ngap_gNB_handle_pdusession_release_command(sctp_assoc_t assoc_id, uin for (i = 0; i < ie->value.choice.PDUSessionResourceToReleaseListRelCmd.list.count; i++) { NGAP_PDUSessionResourceToReleaseItemRelCmd_t *item_p; item_p = ie->value.choice.PDUSessionResourceToReleaseListRelCmd.list.array[i]; - msg->pdusession_release_params[i].pdusession_id = item_p->pDUSessionID; - allocCopy(&msg->pdusession_release_params[i].data, item_p->pDUSessionResourceReleaseCommandTransfer); + pdusession_release_t *r = &msg->pdusession_release_params[i]; + r->pdusession_id = item_p->pDUSessionID; + r->data = create_byte_array(item_p->pDUSessionResourceReleaseCommandTransfer.size, item_p->pDUSessionResourceReleaseCommandTransfer.buf); } itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); diff --git a/openair3/NGAP/ngap_gNB_itti_messaging.c b/openair3/NGAP/ngap_gNB_itti_messaging.c index 87eb93c8f6..b640f2e556 100644 --- a/openair3/NGAP/ngap_gNB_itti_messaging.c +++ b/openair3/NGAP/ngap_gNB_itti_messaging.c @@ -64,9 +64,7 @@ void ngap_gNB_itti_send_nas_downlink_ind(instance_t instance, uint32_t gNB_ue_ng ngap_downlink_nas = &message_p->ittiMsg.ngap_downlink_nas; ngap_downlink_nas->gNB_ue_ngap_id = gNB_ue_ngap_id; - ngap_downlink_nas->nas_pdu.buffer = malloc(sizeof(uint8_t) * nas_pdu_length); - memcpy(ngap_downlink_nas->nas_pdu.buffer, nas_pdu, nas_pdu_length); - ngap_downlink_nas->nas_pdu.length = nas_pdu_length; + ngap_downlink_nas->nas_pdu = create_byte_array(nas_pdu_length, nas_pdu); itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p); } diff --git a/openair3/NGAP/ngap_gNB_management_procedures.c b/openair3/NGAP/ngap_gNB_management_procedures.c index 9615dc6b2a..e82fd1401b 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.c +++ b/openair3/NGAP/ngap_gNB_management_procedures.c @@ -38,6 +38,7 @@ #include "ngap_gNB_defs.h" #include "queue.h" #include "tree.h" +#include "ds/byte_array.h" static ngap_gNB_internal_data_t ngap_gNB_internal_data; diff --git a/openair3/NGAP/ngap_gNB_management_procedures.h b/openair3/NGAP/ngap_gNB_management_procedures.h index fa62f53382..d71480da30 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.h +++ b/openair3/NGAP/ngap_gNB_management_procedures.h @@ -28,6 +28,8 @@ * @ingroup _ngap */ +#include "ds/byte_array.h" + #ifndef NGAP_GNB_MANAGEMENT_PROCEDURES_H_ #define NGAP_GNB_MANAGEMENT_PROCEDURES_H_ diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index a86ba83442..2892678da3 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -58,15 +58,6 @@ #include "s1ap_messages_types.h" #include "xer_encoder.h" -static void allocCopy(OCTET_STRING_t *out, ngap_pdu_t in) -{ - if (in.length) { - out->buf = malloc(in.length); - memcpy(out->buf, in.buffer, in.length); - } - out->size = in.length; -} - static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in) { if (in.length) { @@ -203,7 +194,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_NAS_PDU; - allocCopy(&ie->value.choice.NAS_PDU, UEfirstReq->nas_pdu); + OCTET_STRING_fromBuf(&ie->value.choice.NAS_PDU, (const char *)UEfirstReq->nas_pdu.buf, UEfirstReq->nas_pdu.len); } /* mandatory */ @@ -436,8 +427,8 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_ ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_UplinkNASTransport_IEs__value_PR_NAS_PDU; - ie->value.choice.NAS_PDU.buf = ngap_uplink_nas_p->nas_pdu.buffer; - ie->value.choice.NAS_PDU.size = ngap_uplink_nas_p->nas_pdu.length; + ie->value.choice.NAS_PDU.buf = ngap_uplink_nas_p->nas_pdu.buf; + ie->value.choice.NAS_PDU.size = ngap_uplink_nas_p->nas_pdu.len; } /* mandatory */ { @@ -532,8 +523,8 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance, ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; ie->criticality = NGAP_Criticality_ignore; ie->value.present = NGAP_NASNonDeliveryIndication_IEs__value_PR_NAS_PDU; - ie->value.choice.NAS_PDU.buf = ngap_nas_non_delivery_ind->nas_pdu.buffer; - ie->value.choice.NAS_PDU.size = ngap_nas_non_delivery_ind->nas_pdu.length; + ie->value.choice.NAS_PDU.buf = ngap_nas_non_delivery_ind->nas_pdu.buf; + ie->value.choice.NAS_PDU.size = ngap_nas_non_delivery_ind->nas_pdu.len; } /* mandatory */ { @@ -861,8 +852,8 @@ int ngap_gNB_ue_capabilities(instance_t instance, ngap_ue_cap_info_ind_t *ue_cap ie->id = NGAP_ProtocolIE_ID_id_UERadioCapability; ie->criticality = NGAP_Criticality_ignore; ie->value.present = NGAP_UERadioCapabilityInfoIndicationIEs__value_PR_UERadioCapability; - ie->value.choice.UERadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer; - ie->value.choice.UERadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length; + ie->value.choice.UERadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buf; + ie->value.choice.UERadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.len; } /* optional */ //NGAP_UERadioCapabilityForPaging TBD @@ -1224,8 +1215,9 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas for (i = 0; i < pdusession_release_resp_p->nb_of_pdusessions_released; i++) { asn1cSequenceAdd(ie->value.choice.PDUSessionResourceReleasedListRelRes.list, NGAP_PDUSessionResourceReleasedItemRelRes_t, item); - item->pDUSessionID = pdusession_release_resp_p->pdusession_release[i].pdusession_id; - allocCopy(&item->pDUSessionResourceReleaseResponseTransfer, pdusession_release_resp_p->pdusession_release[i].data); + pdusession_release_t *r = &pdusession_release_resp_p->pdusession_release[i]; + item->pDUSessionID = r->pdusession_id; + OCTET_STRING_fromBuf(&item->pDUSessionResourceReleaseResponseTransfer, (const char *)r->data.buf, r->data.len); NGAP_DEBUG("pdusession_release_resp: pdusession ID %ld\n", item->pDUSessionID); } } From afe73820d6977342432af9c74e10ee9883faffd6 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 23 Sep 2024 15:34:28 +0200 Subject: [PATCH 4/8] Refactor and cleanup rrc_gNB_send_NGAP_NAS_FIRST_REQ * add function to process AMF Identifier * add function to select AMF * set const parameters in utility nnsf functions * adopt utilities for memory allocation * improve readability and maintainability * improve logging --- openair2/RRC/NR/rrc_gNB_NGAP.c | 49 +++-- openair3/NGAP/ngap_gNB_nas_procedures.c | 244 ++++++++++++------------ openair3/NGAP/ngap_gNB_nnsf.c | 28 ++- openair3/NGAP/ngap_gNB_nnsf.h | 28 ++- 4 files changed, 173 insertions(+), 176 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 85d9cffeb3..0749fc12aa 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -148,26 +148,38 @@ void nr_rrc_pdcp_config_security(gNB_RRC_UE_t *UE, bool enable_ciphering) nr_pdcp_config_set_security(UE->rrc_ue_id, DL_SCH_LCID_DCCH, true, &security_parameters); } -//------------------------------------------------------------------------------ -/* -* Initial UE NAS message on S1AP. -*/ +/** @brief Process AMF Identifier and fill GUAMI struct members */ +static nr_guami_t get_guami(const uint32_t amf_Id) +{ + nr_guami_t guami = {0}; + guami.amf_region_id = (amf_Id >> 16) & 0xff; + guami.amf_set_id = (amf_Id >> 6) & 0x3ff; + guami.amf_pointer = amf_Id & 0x3f; + return guami; +} + +/** + * @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 + */ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRCSetupComplete_IEs_t *rrcSetupComplete) -//------------------------------------------------------------------------------ { MessageDef *message_p = itti_alloc_new_message(TASK_RRC_GNB, rrc->module_id, NGAP_NAS_FIRST_REQ); ngap_nas_first_req_t *req = &NGAP_NAS_FIRST_REQ(message_p); memset(req, 0, sizeof(*req)); + // RAN UE NGAP ID req->gNB_ue_ngap_id = UE->rrc_ue_id; + // RRC Establishment Cause /* Assume that cause is coded in the same way in RRC and NGap, just check that the value is in NGap range */ AssertFatal(UE->establishment_cause < NGAP_RRC_CAUSE_LAST, "Establishment cause invalid (%jd/%d)!", UE->establishment_cause, NGAP_RRC_CAUSE_LAST); req->establishment_cause = UE->establishment_cause; - /* Forward NAS message */ + // NAS-PDU req->nas_pdu = create_byte_array(rrcSetupComplete->dedicatedNAS_Message.size, rrcSetupComplete->dedicatedNAS_Message.buf); + // Selected PLMN Identity: indicates the selected PLMN id for the non-3GPP access /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */ int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; if (selected_plmn_identity != 0) @@ -175,32 +187,29 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC req->selected_plmn_identity = 0; /* always zero because we only support one */ - /* Fill UE identities with available information */ + /* 5G-S-TMSI */ if (UE->Initialue_identity_5g_s_TMSI.presence) { - /* Fill s-TMSI */ + // 5G-S-TMSI req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_FiveG_s_tmsi; req->ue_identity.s_tmsi.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id; req->ue_identity.s_tmsi.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer; req->ue_identity.s_tmsi.m_tmsi = UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi; } else if (rrcSetupComplete->registeredAMF != NULL) { + /** + * Fetch the AMF-Identifier from the registeredAMF IE + * The IE AMF-Identifier (AMFI) comprises of an AMF Region ID (8b), + * an AMF Set ID (10b) and an AMF Pointer (6b) + * as specified in TS 23.003 [21], clause 2.10.1. */ NR_RegisteredAMF_t *r_amf = rrcSetupComplete->registeredAMF; req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_guami; - - /* The IE AMF-Identifier (AMFI) comprises of an AMF Region ID (8b), an AMF Set ID (10b) and an AMF Pointer (6b) as specified in TS 23.003 [21], clause 2.10.1. */ uint32_t amf_Id = BIT_STRING_to_uint32(&r_amf->amf_Identifier); - req->ue_identity.guami.amf_region_id = (amf_Id >> 16) & 0xff; - req->ue_identity.guami.amf_set_id = (amf_Id >> 6) & 0x3ff; - req->ue_identity.guami.amf_pointer = amf_Id & 0x3f; - - UE->ue_guami.amf_region_id = req->ue_identity.guami.amf_region_id; - UE->ue_guami.amf_set_id = req->ue_identity.guami.amf_set_id; - UE->ue_guami.amf_pointer = req->ue_identity.guami.amf_pointer; - + UE->ue_guami = req->ue_identity.guami = get_guami(amf_Id); LOG_I(NGAP, - "Build NGAP_NAS_FIRST_REQ adding in s_TMSI: GUAMI amf_set_id %u amf_region_id %u ue %x\n", + "GUAMI in NGAP_NAS_FIRST_REQ (UE %04x): AMF Set ID %u, Region ID %u, Pointer %u\n", + UE->rnti, req->ue_identity.guami.amf_set_id, req->ue_identity.guami.amf_region_id, - UE->rnti); + req->ue_identity.guami.amf_pointer); } else { req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_NONE; } diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 2892678da3..5fe80db46e 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -68,20 +68,104 @@ static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in) } } -//------------------------------------------------------------------------------ -int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEfirstReq) -//------------------------------------------------------------------------------ +/** @brief Selects the AMF instance for a given UE based on identity information. + * It attempts to select an AMF using the following prioritized criteria: + * 1. GUAMI, if provided and valid (via Region ID, Set ID, Pointer). + * 2. 5G-S-TMSI, using AMF Set ID if GUAMI is unavailable or unusable. + * 3. Selected PLMN identity and local PLMN configuration. + * 4. Fallback to AMF with highest relative capacity, considering load balancing. + * @ref AMF Discovery and Selection (3GPP TS 23.501 clause 6.3.5) */ +static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ngap_nas_first_req_t *msg) { - ngap_gNB_instance_t *instance_p = NULL; - struct ngap_gNB_amf_data_s *amf_desc_p = NULL; - NGAP_NGAP_PDU_t pdu; - uint8_t *buffer = NULL; - uint32_t length = 0; + ngap_gNB_amf_data_t *amf = NULL; + + /* Select the AMF corresponding to the provided GUAMI. */ + if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_guami) { + const nr_guami_t *guami = &msg->ue_identity.guami; + amf = ngap_gNB_nnsf_select_amf_by_guami(instance_p, msg->establishment_cause, *guami); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + guami->mcc, + guami->mnc, + guami->amf_region_id, + guami->amf_set_id, + guami->amf_pointer); + } + } + + if (amf == NULL) { + /* Select the AMF corresponding to the provided s-TMSI. */ + //TODO have not be test. it's should be test + if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) { + const fiveg_s_tmsi_t *fgs_tmsi = &msg->ue_identity.s_tmsi; + amf = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, msg->establishment_cause, msg->selected_plmn_identity, fgs_tmsi->amf_set_id); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + fgs_tmsi->amf_set_id, + msg->selected_plmn_identity, + instance_p->plmn[msg->selected_plmn_identity].plmn.mcc, + instance_p->plmn[msg->selected_plmn_identity].plmn.mnc); + } + } + } + + if (amf == NULL) { + /* Select AMF based on the selected PLMN identity, received through RRC + * Connection Setup Complete */ + amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->selected_plmn_identity); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + msg->selected_plmn_identity, + instance_p->plmn[msg->selected_plmn_identity].plmn.mcc, + instance_p->plmn[msg->selected_plmn_identity].plmn.mnc); + } + } + + if (amf == NULL) { + /* + * If no AMF corresponds to the GUAMI, the s-TMSI, or the selected PLMN + * identity, selects the AMF with the highest capacity. + */ + amf = ngap_gNB_nnsf_select_amf(instance_p, msg->establishment_cause); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id); + } + } + + return amf; +} + +/** @brief NAS Transport Messages: Initial UE Message + * forward the first received (layer 3) uplink NAS message + * from the radio interface to the AMF over N2 + * NG-RAN node -> AMF (9.2.5.1, 3GPP TS 38.413) */ +int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEfirstReq) +{ + NGAP_NGAP_PDU_t pdu = {0}; + uint8_t *buffer = NULL; + uint32_t length = 0; DevAssert(UEfirstReq != NULL); /* Retrieve the NGAP gNB instance associated with Mod_id */ - instance_p = ngap_gNB_get_instance(instance); + ngap_gNB_instance_t *instance_p = ngap_gNB_get_instance(instance); DevAssert(instance_p != NULL); - memset(&pdu, 0, sizeof(pdu)); + + // AMF selection from the Initial UE message contents + struct ngap_gNB_amf_data_s *amf = select_amf(instance_p, UEfirstReq); + if (amf == NULL) { + NGAP_WARN("No AMF is associated to the gNB\n"); + return -1; + } + + // Message Type (M) pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; asn1cCalloc(pdu.choice.initiatingMessage, head); head->procedureCode = NGAP_ProcedureCode_id_InitialUEMessage; @@ -89,98 +173,18 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf head->value.present = NGAP_InitiatingMessage__value_PR_InitialUEMessage; NGAP_InitialUEMessage_t *out = &head->value.choice.InitialUEMessage; - /* Select the AMF corresponding to the provided GUAMI. */ - //TODO have not be test. it's should be test - if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_guami) { - amf_desc_p = ngap_gNB_nnsf_select_amf_by_guami(instance_p, UEfirstReq->establishment_cause, UEfirstReq->ue_identity.guami); - - if (amf_desc_p) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n", - UEfirstReq->gNB_ue_ngap_id, - amf_desc_p->amf_name, - amf_desc_p->assoc_id, - UEfirstReq->ue_identity.guami.mcc, - UEfirstReq->ue_identity.guami.mnc, - UEfirstReq->ue_identity.guami.amf_region_id, - UEfirstReq->ue_identity.guami.amf_set_id, - UEfirstReq->ue_identity.guami.amf_pointer); - } - } - - if (amf_desc_p == NULL) { - /* Select the AMF corresponding to the provided s-TMSI. */ - //TODO have not be test. it's should be test - if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) { - amf_desc_p = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, UEfirstReq->establishment_cause, UEfirstReq->selected_plmn_identity, UEfirstReq->ue_identity.s_tmsi.amf_set_id); - - if (amf_desc_p) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n", - UEfirstReq->gNB_ue_ngap_id, - amf_desc_p->amf_name, - amf_desc_p->assoc_id, - UEfirstReq->ue_identity.s_tmsi.amf_set_id, - UEfirstReq->selected_plmn_identity, - instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mcc, - instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mnc); - } - } - } - - if (amf_desc_p == NULL) { - /* Select AMF based on the selected PLMN identity, received through RRC - * Connection Setup Complete */ - //TODO have not be test. it's should be test - amf_desc_p = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, UEfirstReq->establishment_cause, UEfirstReq->selected_plmn_identity); - - if (amf_desc_p) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n", - UEfirstReq->gNB_ue_ngap_id, - amf_desc_p->amf_name, - amf_desc_p->assoc_id, - UEfirstReq->selected_plmn_identity, - instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mcc, - instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mnc); - } - } - - if (amf_desc_p == NULL) { - /* - * If no AMF corresponds to the GUAMI, the s-TMSI, or the selected PLMN - * identity, selects the AMF with the highest capacity. - */ - //TODO have not be test. it's should be test - amf_desc_p = ngap_gNB_nnsf_select_amf(instance_p, UEfirstReq->establishment_cause); - - if (amf_desc_p) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", UEfirstReq->gNB_ue_ngap_id, amf_desc_p->amf_name, amf_desc_p->assoc_id); - } - } - - if (amf_desc_p == NULL) { - /* - * In case gNB has no AMF associated, the gNB should inform RRC and discard - * this request. - */ - NGAP_WARN("No AMF is associated to the gNB\n"); - // TODO: Inform RRC - return -1; - } - - /* The gNB should allocate a unique gNB UE NGAP ID for this UE. The value - * will be used for the duration of the connectivity. - */ - struct ngap_gNB_ue_context_s *ue_desc_p = calloc(1, sizeof(*ue_desc_p)); + /* Store the UE context in NGAP with: + * selected AMF, selected PLMN identity, gNB ID + * the unique gNB UE NGAP ID, used for the duration of the connectivity */ + struct ngap_gNB_ue_context_s *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p)); DevAssert(ue_desc_p != NULL); - /* Keep a reference to the selected AMF */ - ue_desc_p->amf_ref = amf_desc_p; + ue_desc_p->amf_ref = amf; ue_desc_p->gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id; ue_desc_p->gNB_instance = instance_p; ue_desc_p->selected_plmn_identity = UEfirstReq->selected_plmn_identity; - - // insert in master table ngap_store_ue_context(ue_desc_p); - /* mandatory */ + // RAN UE NGAP ID (M) { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; @@ -188,7 +192,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_RAN_UE_NGAP_ID; ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p->gNB_ue_ngap_id; } - /* mandatory */ + + /* NAS-PDU (M): transferred transparently */ { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; @@ -197,38 +202,33 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf OCTET_STRING_fromBuf(&ie->value.choice.NAS_PDU, (const char *)UEfirstReq->nas_pdu.buf, UEfirstReq->nas_pdu.len); } - /* mandatory */ + // User Location Information (M) { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_UserLocationInformation; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_UserLocationInformation; - ie->value.choice.UserLocationInformation.present = NGAP_UserLocationInformation_PR_userLocationInformationNR; - asn1cCalloc(ie->value.choice.UserLocationInformation.choice.userLocationInformationNR, userinfo_nr_p); /* Set nRCellIdentity. default userLocationInformationNR */ MACRO_GNB_ID_TO_CELL_IDENTITY(instance_p->gNB_id, 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - MCC_MNC_TO_TBCD(instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mcc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc_digit_length, - &userinfo_nr_p->nR_CGI.pLMNIdentity); - /* Set TAI */ + plmn_id_t *plmn = &instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn; + MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); + + /* In case of network sharing, + the selected PLMN is indicated by the PLMN Identity IE within the TAI IE */ INT24_TO_OCTET_STRING(instance_p->tac, &userinfo_nr_p->tAI.tAC); - MCC_MNC_TO_PLMNID(instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mcc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc_digit_length, - &userinfo_nr_p->tAI.pLMNIdentity); + MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity); } /* Set the establishment cause according to those provided by RRC */ DevCheck(UEfirstReq->establishment_cause < NGAP_RRC_CAUSE_LAST, UEfirstReq->establishment_cause, NGAP_RRC_CAUSE_LAST, 0); - /* mandatory */ + // RRC Establishment Cause (M) { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_RRCEstablishmentCause; @@ -237,7 +237,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->value.choice.RRCEstablishmentCause = UEfirstReq->establishment_cause; } - /* optional */ + // 5G-S-TMSI (O) if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) { NGAP_DEBUG("FIVEG_S_TMSI_PRESENT\n"); asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); @@ -249,7 +249,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf M_TMSI_TO_OCTET_STRING(UEfirstReq->ue_identity.s_tmsi.m_tmsi, &ie->value.choice.FiveG_S_TMSI.fiveG_TMSI); } - /* optional */ + /* UE Context Request (O): instruct the AMF to trigger an + Initial Context Setup procedure towards the NG-RAN node. */ { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_UEContextRequest; @@ -258,10 +259,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->value.choice.UEContextRequest = NGAP_UEContextRequest_requested; } - if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { - /* Failed to encode message */ - DevMessage("Failed to encode initial UE message\n"); - } + if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) + DevMessage("Failed to encode initial UE message\n"); /* Update the current NGAP UE state */ ue_desc_p->ue_state = NGAP_UE_WAITING_CSR; @@ -277,16 +276,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf * the stream should not be changed during the communication of the * UE-associated signalling. */ - amf_desc_p->nextstream = (amf_desc_p->nextstream + 1) % amf_desc_p->out_streams; - - if ((amf_desc_p->nextstream == 0) && (amf_desc_p->out_streams > 1)) { - amf_desc_p->nextstream += 1; + amf->nextstream = (amf->nextstream + 1) % amf->out_streams; + if ((amf->nextstream == 0) && (amf->out_streams > 1)) { + amf->nextstream += 1; } - - ue_desc_p->tx_stream = amf_desc_p->nextstream; + ue_desc_p->tx_stream = amf->nextstream; /* Send encoded message over sctp */ - ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf_desc_p->assoc_id, - buffer, length, ue_desc_p->tx_stream); + ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p->tx_stream); return 0; } diff --git a/openair3/NGAP/ngap_gNB_nnsf.c b/openair3/NGAP/ngap_gNB_nnsf.c index 54c8a505bb..648d455bea 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.c +++ b/openair3/NGAP/ngap_gNB_nnsf.c @@ -33,9 +33,7 @@ #include "queue.h" #include "tree.h" -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL; @@ -86,10 +84,9 @@ ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, return amf_highest_capacity_p; } -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - int selected_plmn_identity) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const int selected_plmn_identity) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL; @@ -156,11 +153,10 @@ ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, return amf_highest_capacity_p; } -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - int selected_plmn_identity, - uint8_t amf_setid) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const int selected_plmn_identity, + uint8_t amf_setid) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; @@ -234,9 +230,9 @@ ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, return NULL; } -struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - nr_guami_t guami) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const nr_guami_t guami) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; @@ -326,7 +322,7 @@ struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_ return NULL; } -struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, nr_guami_t guami) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, const nr_guami_t guami) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL; diff --git a/openair3/NGAP/ngap_gNB_nnsf.h b/openair3/NGAP/ngap_gNB_nnsf.h index 8b20b0cad4..074b163f75 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.h +++ b/openair3/NGAP/ngap_gNB_nnsf.h @@ -34,25 +34,21 @@ #include "ngap_gNB_defs.h" #include "ngap_messages_types.h" -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause); -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - int selected_plmn_identity); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const int selected_plmn_identity); -struct ngap_gNB_amf_data_s* -ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - int selected_plmn_identity, - uint8_t amf_setid); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const int selected_plmn_identity, + uint8_t amf_setid); -struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - nr_guami_t guami); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const nr_guami_t guami); -struct ngap_gNB_amf_data_s *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, nr_guami_t guami); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, const nr_guami_t guami); #endif /* NGAP_GNB_NNSF_H_ */ From 8a0baed43094531eee6487c8e12f40c8d021e900 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 8 May 2025 15:31:42 +0200 Subject: [PATCH 5/8] Handle both 5G-S-TMSI and GUAMI in the NGAP Initial UE Message procedures * use bitmask to select presence of either 5G-S-TMSI or GUAMI * select the AMF based on (1) absence of UE Identity (2) Presence of GUAMI (3) Presence of 5G-S-TMSI Related to #801 --- openair2/COMMON/ngap_messages_types.h | 1 - openair2/RRC/NR/rrc_gNB_NGAP.c | 15 +++++----- openair3/NGAP/ngap_gNB_nas_procedures.c | 38 ++++++++++++++----------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index f833fbdbf0..e54bc46d09 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -217,7 +217,6 @@ typedef struct ngap_ue_paging_identity_s { } ngap_ue_paging_identity_t; typedef enum ngap_ue_identities_presenceMask_e { - NGAP_UE_IDENTITIES_NONE = 0, NGAP_UE_IDENTITIES_FiveG_s_tmsi = 1 << 1, NGAP_UE_IDENTITIES_guami = 1 << 2, } ngap_ue_identities_presenceMask_t; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 0749fc12aa..879141144e 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -189,19 +189,20 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC /* 5G-S-TMSI */ if (UE->Initialue_identity_5g_s_TMSI.presence) { - // 5G-S-TMSI - req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_FiveG_s_tmsi; + req->ue_identity.presenceMask |= NGAP_UE_IDENTITIES_FiveG_s_tmsi; req->ue_identity.s_tmsi.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id; req->ue_identity.s_tmsi.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer; req->ue_identity.s_tmsi.m_tmsi = UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi; - } else if (rrcSetupComplete->registeredAMF != NULL) { - /** - * Fetch the AMF-Identifier from the registeredAMF IE + } + + /* Process Registered AMF IE */ + if (rrcSetupComplete->registeredAMF != NULL) { + /* Fetch the AMF-Identifier from the registeredAMF IE * The IE AMF-Identifier (AMFI) comprises of an AMF Region ID (8b), * an AMF Set ID (10b) and an AMF Pointer (6b) * as specified in TS 23.003 [21], clause 2.10.1. */ NR_RegisteredAMF_t *r_amf = rrcSetupComplete->registeredAMF; - req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_guami; + req->ue_identity.presenceMask |= NGAP_UE_IDENTITIES_guami; uint32_t amf_Id = BIT_STRING_to_uint32(&r_amf->amf_Identifier); UE->ue_guami = req->ue_identity.guami = get_guami(amf_Id); LOG_I(NGAP, @@ -210,8 +211,6 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC req->ue_identity.guami.amf_set_id, req->ue_identity.guami.amf_region_id, req->ue_identity.guami.amf_pointer); - } else { - req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_NONE; } itti_send_msg_to_task(TASK_NGAP, rrc->module_id, message_p); diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 5fe80db46e..36e9934384 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -79,9 +79,15 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng { ngap_gNB_amf_data_t *amf = NULL; - /* Select the AMF corresponding to the provided GUAMI. */ + // Select the AMF corresponding to the GUAMI from the RegisteredAMF IE if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_guami) { const nr_guami_t *guami = &msg->ue_identity.guami; + NGAP_DEBUG("GUAMI is present: MCC=%03d MNC=%03d RegionID=%d SetID=%d Pointer=%d\n", + guami->mcc, + guami->mnc, + guami->amf_region_id, + guami->amf_set_id, + guami->amf_pointer); amf = ngap_gNB_nnsf_select_amf_by_guami(instance_p, msg->establishment_cause, *guami); if (amf) { NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n", @@ -93,12 +99,12 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng guami->amf_region_id, guami->amf_set_id, guami->amf_pointer); + return amf; } } + // Select the AMF corresponding to the provided 5G-S-TMSI if (amf == NULL) { - /* Select the AMF corresponding to the provided s-TMSI. */ - //TODO have not be test. it's should be test if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) { const fiveg_s_tmsi_t *fgs_tmsi = &msg->ue_identity.s_tmsi; amf = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, msg->establishment_cause, msg->selected_plmn_identity, fgs_tmsi->amf_set_id); @@ -111,13 +117,14 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng msg->selected_plmn_identity, instance_p->plmn[msg->selected_plmn_identity].plmn.mcc, instance_p->plmn[msg->selected_plmn_identity].plmn.mnc); + return amf; } } } - if (amf == NULL) { - /* Select AMF based on the selected PLMN identity, received through RRC - * Connection Setup Complete */ + // No UE identity (5G-S-TMSI or GUAMI) is present + if (msg->ue_identity.presenceMask == 0) { + // Select the AMF based on the selected PLMN identity received through RRCSetupComplete amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->selected_plmn_identity); if (amf) { NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n", @@ -127,17 +134,14 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng msg->selected_plmn_identity, instance_p->plmn[msg->selected_plmn_identity].plmn.mcc, instance_p->plmn[msg->selected_plmn_identity].plmn.mnc); - } - } - - if (amf == NULL) { - /* - * If no AMF corresponds to the GUAMI, the s-TMSI, or the selected PLMN - * identity, selects the AMF with the highest capacity. - */ - amf = ngap_gNB_nnsf_select_amf(instance_p, msg->establishment_cause); - if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id); + return amf; + } else { + // Select the AMF with the highest capacity + amf = ngap_gNB_nnsf_select_amf(instance_p, msg->establishment_cause); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id); + return amf; + } } } From 539d17203f947c1a6bf0246bd0e58ebd97661934 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 8 May 2025 17:10:50 +0200 Subject: [PATCH 6/8] Fix handling of selected PLMN in NGAP selectedPLMN-Identity IE in RRCSetupComplete is an Index (long) of the PLMN selected by the UE from the plmn-IdentityInfoList (SIB1) (see 3GPP TS 38.331) while Selected PLMN Identity in NGAP INITIAL UE MESSAGE Indicates the selected PLMN id for the non-3GPP access (PLMN Identity ID carrying MNC, MCC and MNC size, 9.2.5.1 3GPP TS 38.413) The legacy code was setting Selected PLMN Identity in the latter to an ID value as the former, however in NGAP the IE to be encoded is PLMN Identity 9.3.3.5 therefore: * set plmn type plmn_id_t in ngap_nas_first_req_t * check whether received selectedPLMN-Identity is within bounds * select PLMN from gNB_RrcConfigurationReq by selectedPLMN-Identity ID note: this commit is assuming that the plmn-IdentityInfoList in SIB1 is matching the PLMN list in gNB_RrcConfigurationReq * in NGAP: store the PLMN in the NGAP UE context, no need to fetch the PLMN in the NGAP instance since the UE context already tells what PLMN was selected Closes #801 --- openair2/COMMON/ngap_messages_types.h | 20 ++++++--------- openair2/RRC/NR/rrc_gNB_NGAP.c | 27 +++++++++++++------- openair3/NGAP/ngap_gNB_nas_procedures.c | 33 ++++++++++--------------- openair3/NGAP/ngap_gNB_nnsf.c | 10 +++----- openair3/NGAP/ngap_gNB_nnsf.h | 4 +-- openair3/NGAP/ngap_gNB_ue_context.h | 2 +- 6 files changed, 45 insertions(+), 51 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index e54bc46d09..52cd919338 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -490,22 +490,16 @@ typedef struct ngap_deregistered_gnb_ind_s { * will be the unique identifier used between RRC and NGAP. */ typedef struct ngap_nas_first_req_s { - /* UE id for initial connection to NGAP */ + // RAN UE NGAP ID (mandatory) uint32_t gNB_ue_ngap_id; - - /* the chosen PLMN identity as index, see TS 36.331 6.2.2 RRC Connection - * Setup Complete. This index here is zero-based, unlike the standard! */ - int selected_plmn_identity; - - /* Establishment cause as sent by UE */ + /* PLMN: Selected PLMN Identity (optional) + * User Location Information (mandatory) */ + plmn_id_t plmn; + // RRC Establishment Cause (mandatory) ngap_rrc_establishment_cause_t establishment_cause; - - /* NAS PDU */ + // NAS-PDU (mandatory) byte_array_t nas_pdu; - - /* If this flag is set NGAP layer is expecting the GUAMI. If = 0, - * the temporary s-tmsi is used. - */ + // UE identity: 5G-S-TMSI, GUAMI ngap_ue_identity_t ue_identity; } ngap_nas_first_req_t; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 879141144e..5dc101411c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -149,12 +149,15 @@ void nr_rrc_pdcp_config_security(gNB_RRC_UE_t *UE, bool enable_ciphering) } /** @brief Process AMF Identifier and fill GUAMI struct members */ -static nr_guami_t get_guami(const uint32_t amf_Id) +static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn) { nr_guami_t guami = {0}; guami.amf_region_id = (amf_Id >> 16) & 0xff; guami.amf_set_id = (amf_Id >> 6) & 0x3ff; guami.amf_pointer = amf_Id & 0x3f; + guami.mcc = plmn.mcc; + guami.mnc = plmn.mnc; + guami.mnc_len = plmn.mnc_digit_length; return guami; } @@ -179,13 +182,19 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC // NAS-PDU req->nas_pdu = create_byte_array(rrcSetupComplete->dedicatedNAS_Message.size, rrcSetupComplete->dedicatedNAS_Message.buf); - // Selected PLMN Identity: indicates the selected PLMN id for the non-3GPP access - /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */ - int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; - if (selected_plmn_identity != 0) - LOG_E(NGAP, "UE %u: sent selected PLMN identity %ld, but only one PLMN supported\n", req->gNB_ue_ngap_id, rrcSetupComplete->selectedPLMN_Identity); - - req->selected_plmn_identity = 0; /* always zero because we only support one */ + /* Selected PLMN Identity (Optional) + * selectedPLMN-Identity in RRCSetupComplete: Index of the PLMN selected by the UE from the plmn-IdentityInfoList (SIB1) + * Selected PLMN Identity in INITIAL UE MESSAGE: Indicates the selected PLMN id for the non-3GPP access.*/ + if (rrcSetupComplete->selectedPLMN_Identity > rrc->configuration.num_plmn) { + LOG_E(NGAP, + "Failed to send Initial UE Message: selected PLMN (%ld) identity is out of bounds (%d)\n", + rrcSetupComplete->selectedPLMN_Identity, + rrc->configuration.num_plmn); + return; + } + int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; // Convert 1-based PLMN Identity IE to 0-based index + req->plmn = rrc->configuration.plmn[selected_plmn_identity]; // Select from the stored list + LOG_I(NGAP, "Selected PLMN in the NG Initial UE Message: MCC %u, MNC %u\n", req->plmn.mcc, req->plmn.mnc); /* 5G-S-TMSI */ if (UE->Initialue_identity_5g_s_TMSI.presence) { @@ -204,7 +213,7 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC NR_RegisteredAMF_t *r_amf = rrcSetupComplete->registeredAMF; req->ue_identity.presenceMask |= NGAP_UE_IDENTITIES_guami; uint32_t amf_Id = BIT_STRING_to_uint32(&r_amf->amf_Identifier); - UE->ue_guami = req->ue_identity.guami = get_guami(amf_Id); + UE->ue_guami = req->ue_identity.guami = get_guami(amf_Id, req->plmn); LOG_I(NGAP, "GUAMI in NGAP_NAS_FIRST_REQ (UE %04x): AMF Set ID %u, Region ID %u, Pointer %u\n", UE->rnti, diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 36e9934384..7729ffa4f2 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -107,16 +107,15 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng if (amf == NULL) { if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) { const fiveg_s_tmsi_t *fgs_tmsi = &msg->ue_identity.s_tmsi; - amf = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, msg->establishment_cause, msg->selected_plmn_identity, fgs_tmsi->amf_set_id); + amf = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, msg->establishment_cause, msg->plmn, fgs_tmsi->amf_set_id); if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n", + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN MCC %d MNC %d\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id, fgs_tmsi->amf_set_id, - msg->selected_plmn_identity, - instance_p->plmn[msg->selected_plmn_identity].plmn.mcc, - instance_p->plmn[msg->selected_plmn_identity].plmn.mnc); + msg->plmn.mcc, + msg->plmn.mnc); return amf; } } @@ -125,15 +124,14 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng // No UE identity (5G-S-TMSI or GUAMI) is present if (msg->ue_identity.presenceMask == 0) { // Select the AMF based on the selected PLMN identity received through RRCSetupComplete - amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->selected_plmn_identity); + amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->plmn); if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n", + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN MCC %d MNC %d\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id, - msg->selected_plmn_identity, - instance_p->plmn[msg->selected_plmn_identity].plmn.mcc, - instance_p->plmn[msg->selected_plmn_identity].plmn.mnc); + msg->plmn.mcc, + msg->plmn.mnc); return amf; } else { // Select the AMF with the highest capacity @@ -185,7 +183,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ue_desc_p->amf_ref = amf; ue_desc_p->gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id; ue_desc_p->gNB_instance = instance_p; - ue_desc_p->selected_plmn_identity = UEfirstReq->selected_plmn_identity; + ue_desc_p->selected_plmn_identity = UEfirstReq->plmn; ngap_store_ue_context(ue_desc_p); // RAN UE NGAP ID (M) @@ -220,7 +218,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - plmn_id_t *plmn = &instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn; + plmn_id_t *plmn = &ue_desc_p->selected_plmn_identity; MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); /* In case of network sharing, @@ -444,17 +442,12 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_ MACRO_GNB_ID_TO_CELL_IDENTITY(ngap_gNB_instance_p->gNB_id, 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - MCC_MNC_TO_TBCD(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mcc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc_digit_length, - &userinfo_nr_p->nR_CGI.pLMNIdentity); + plmn_id_t *plmn = &ue_context_p->selected_plmn_identity; + MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); /* Set TAI */ INT24_TO_OCTET_STRING(ngap_gNB_instance_p->tac, &userinfo_nr_p->tAI.tAC); - MCC_MNC_TO_PLMNID(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mcc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc_digit_length, - &userinfo_nr_p->tAI.pLMNIdentity); + MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity); } if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode uplink NAS transport\n"); diff --git a/openair3/NGAP/ngap_gNB_nnsf.c b/openair3/NGAP/ngap_gNB_nnsf.c index 648d455bea..77cc7866e1 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.c +++ b/openair3/NGAP/ngap_gNB_nnsf.c @@ -86,7 +86,7 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, c ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause, - const int selected_plmn_identity) + const plmn_id_t selected_plmn_identity) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL; @@ -132,8 +132,7 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *in /* Looking for served GUAMI PLMN Identity selected matching the one provided by the UE */ STAILQ_FOREACH(guami_p, &amf_data_p->served_guami, next) { STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) { - if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].plmn.mcc) - && (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].plmn.mnc)) { + if ((served_plmn_p->mcc == selected_plmn_identity.mcc) && (served_plmn_p->mnc == selected_plmn_identity.mnc)) { break; } } @@ -155,7 +154,7 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *in ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause, - const int selected_plmn_identity, + const plmn_id_t selected_plmn_identity, uint8_t amf_setid) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; @@ -203,8 +202,7 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t * struct plmn_identity_s *served_plmn_p = NULL; STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) { - if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].plmn.mcc) - && (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].plmn.mnc)) { + if ((served_plmn_p->mcc == selected_plmn_identity.mcc) && (served_plmn_p->mnc == selected_plmn_identity.mnc)) { break; } } diff --git a/openair3/NGAP/ngap_gNB_nnsf.h b/openair3/NGAP/ngap_gNB_nnsf.h index 074b163f75..8a87ecfce2 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.h +++ b/openair3/NGAP/ngap_gNB_nnsf.h @@ -38,11 +38,11 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, c ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause, - const int selected_plmn_identity); + const plmn_id_t selected_plmn_identity); ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause, - const int selected_plmn_identity, + const plmn_id_t selected_plmn_identity, uint8_t amf_setid); ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, diff --git a/openair3/NGAP/ngap_gNB_ue_context.h b/openair3/NGAP/ngap_gNB_ue_context.h index 2ca75141ef..4c0c63239f 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.h +++ b/openair3/NGAP/ngap_gNB_ue_context.h @@ -72,7 +72,7 @@ typedef struct ngap_gNB_ue_context_s { /* Signaled by the UE in RRC Connection Setup Complete and used in NAS Uplink * to route NAS messages correctly. 0-based, not 1-based as in TS 36.331 * 6.2.2 RRC Connection Setup Complete! */ - int selected_plmn_identity; + plmn_id_t selected_plmn_identity; /* Reference to gNB data this UE is attached to */ ngap_gNB_instance_t *gNB_instance; From cc57bcc3a0ea802b0b9d631e3bc38016e1de670c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 12 May 2025 10:03:54 +0200 Subject: [PATCH 7/8] Log served GUAMIs, PLMNs and slices in NG Setup handler --- openair3/NGAP/ngap_gNB_handlers.c | 46 +++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index a93ad76ed7..1ef49f66c0 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -136,6 +136,36 @@ static int ngap_gNB_handle_ng_setup_failure(sctp_assoc_t assoc_id, uint32_t stre return 0; } +static void ngap_dump_served_guami(const ngap_gNB_amf_data_t *amf_desc_p) +{ + const struct served_guami_s *guami_p; + const struct plmn_identity_s *plmn_p; + const struct served_region_id_s *region_p; + const struct amf_set_id_s *set_id_p; + const struct amf_pointer_s *pointer_p; + + NGAP_DEBUG("Served GUAMIs for AMF %s (assoc_id=%d):\n", + amf_desc_p->amf_name ? amf_desc_p->amf_name : "(no name)", + amf_desc_p->assoc_id); + + STAILQ_FOREACH(guami_p, &amf_desc_p->served_guami, next) + { + NGAP_DEBUG(" GUAMI:\n"); + STAILQ_FOREACH(plmn_p, &guami_p->served_plmns, next) { + NGAP_DEBUG(" PLMN: MCC=%03d, MNC=%0*d\n", plmn_p->mcc, plmn_p->mnc_digit_length, plmn_p->mnc); + } + STAILQ_FOREACH(region_p, &guami_p->served_region_ids, next) { + NGAP_DEBUG(" AMF Region ID: %d\n", region_p->amf_region_id); + } + STAILQ_FOREACH(set_id_p, &guami_p->amf_set_ids, next) { + NGAP_DEBUG(" AMF Set ID: %d\n", set_id_p->amf_set_id); + } + STAILQ_FOREACH(pointer_p, &guami_p->amf_pointers, next) { + NGAP_DEBUG(" AMF Pointer: %d\n", pointer_p->amf_pointer); + } + } +} + static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { NGAP_NGSetupResponse_t *container; @@ -164,7 +194,6 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str /* The list of served guami can contain at most 256 elements. * NR related guami is the first element in the list, i.e with an id of 0. */ - NGAP_DEBUG("servedGUAMIs.list.count %d\n", ie->value.choice.ServedGUAMIList.list.count); DevAssert(ie->value.choice.ServedGUAMIList.list.count > 0); DevAssert(ie->value.choice.ServedGUAMIList.list.count <= NGAP_maxnoofServedGUAMIs); @@ -214,6 +243,7 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str STAILQ_INSERT_TAIL(&amf_desc_p->served_guami, new_guami_p, next); } + ngap_dump_served_guami(amf_desc_p); /* Set the capacity of this AMF */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_NGSetupResponseIEs_t, ie, container, @@ -236,7 +266,6 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_NGSetupResponseIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PLMNSupportList, true); - NGAP_DEBUG("PLMNSupportList.list.count %d\n", ie->value.choice.PLMNSupportList.list.count); DevAssert(ie->value.choice.PLMNSupportList.list.count > 0); DevAssert(ie->value.choice.PLMNSupportList.list.count <= NGAP_maxnoofPLMNs); @@ -251,11 +280,10 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str plmn_support_item_p = ie->value.choice.PLMNSupportList.list.array[i]; new_plmn_support_p = calloc(1, sizeof(struct plmn_support_s)); - - TBCD_TO_MCC_MNC(&plmn_support_item_p->pLMNIdentity, new_plmn_support_p->plmn_identity.mcc, - new_plmn_support_p->plmn_identity.mnc, new_plmn_support_p->plmn_identity.mnc_digit_length); - NGAP_DEBUG("PLMNSupportList.list.count %d\n", plmn_support_item_p->sliceSupportList.list.count); + struct plmn_identity_s *plmn = &new_plmn_support_p->plmn_identity; + TBCD_TO_MCC_MNC(&plmn_support_item_p->pLMNIdentity, plmn->mcc, plmn->mnc, plmn->mnc_digit_length); + NGAP_INFO("Supported PLMN %d: MCC=%03d MNC=%0*d\n", i, plmn->mcc, plmn->mnc_digit_length, plmn->mnc); DevAssert(plmn_support_item_p->sliceSupportList.list.count > 0); DevAssert(plmn_support_item_p->sliceSupportList.list.count <= NGAP_maxnoofSliceItems); @@ -273,6 +301,12 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str new_slice_support_p->sD[1] = slice_support_item_p->s_NSSAI.sD->buf[1]; new_slice_support_p->sD[2] = slice_support_item_p->s_NSSAI.sD->buf[2]; } + NGAP_INFO("Supported slice (PLMN %d): SST=0x%02x SD=%d%d%d\n", + i, + new_slice_support_p->sST, + new_slice_support_p->sD[0], + new_slice_support_p->sD[1], + new_slice_support_p->sD[2]); STAILQ_INSERT_TAIL(&new_plmn_support_p->slice_supports, new_slice_support_p, next); } From 4ad2a78706f42c64a7536da560ca665a258a240e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 12 May 2025 15:57:16 +0200 Subject: [PATCH 8/8] Fix GUAMI decoding in NG Setup Response handler GUAMI fields (Set ID, Pointer and Region ID) were decoded as Octet String, however they are encoded as BIT STRING. Therefore, the GUAMI value was wrongly decoded. In the AMF logs the AMF IDs are 1,1,1, however in gNB logs we had 1,64,4 Quick local test confirmed that: ---- TESTING AMF IDs = 1 ---- Region ID (OCTET STRING): 1 Region ID (BIT STRING): 1 Set ID (OCTET STRING): 64 Set ID (BIT STRING): 1 Pointer (OCTET STRING): 4 Pointer (BIT STRING): 1 The difference arises because: - OCTET STRING treats the buffer as raw bytes, with all bits used. - BIT STRING includes a `bits_unused` field, which tells how many padding bits are present in the least significant end. This is especially important in 3GPP ASN.1 definitions like AMF Set ID (10 bits), AMF Region ID (8 bits), AMF Pointer (6 bits), where the full byte(s) may contain unused bits that must be masked out. --- openair3/NGAP/ngap_gNB_handlers.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 1ef49f66c0..ad8efce5a3 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -217,27 +217,21 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str STAILQ_INSERT_TAIL(&new_guami_p->served_plmns, new_plmn_identity_p, next); new_guami_p->nb_served_plmns++; - NGAP_AMFRegionID_t *amf_region_id_p; struct served_region_id_s *new_region_id_p; - amf_region_id_p = &guami_item_p->gUAMI.aMFRegionID; new_region_id_p = calloc(1, sizeof(struct served_region_id_s)); - OCTET_STRING_TO_INT8(amf_region_id_p, new_region_id_p->amf_region_id); + new_region_id_p->amf_region_id = BIT_STRING_to_uint8(&guami_item_p->gUAMI.aMFRegionID); STAILQ_INSERT_TAIL(&new_guami_p->served_region_ids, new_region_id_p, next); new_guami_p->nb_region_id++; - NGAP_AMFSetID_t *amf_set_id_p; struct amf_set_id_s *new_amf_set_id_p; - amf_set_id_p = &guami_item_p->gUAMI.aMFSetID; new_amf_set_id_p = calloc(1, sizeof(struct amf_set_id_s)); - OCTET_STRING_TO_INT16(amf_set_id_p, new_amf_set_id_p->amf_set_id); + new_amf_set_id_p->amf_set_id = BIT_STRING_to_uint16(&guami_item_p->gUAMI.aMFSetID); STAILQ_INSERT_TAIL(&new_guami_p->amf_set_ids, new_amf_set_id_p, next); new_guami_p->nb_amf_set_id++; - NGAP_AMFPointer_t *amf_pointer_p; struct amf_pointer_s *new_amf_pointer_p; - amf_pointer_p = &guami_item_p->gUAMI.aMFPointer; new_amf_pointer_p = calloc(1, sizeof(struct amf_pointer_s)); - OCTET_STRING_TO_INT8(amf_pointer_p, new_amf_pointer_p->amf_pointer); + new_amf_pointer_p->amf_pointer = BIT_STRING_to_uint8(&guami_item_p->gUAMI.aMFPointer); STAILQ_INSERT_TAIL(&new_guami_p->amf_pointers, new_amf_pointer_p, next); new_guami_p->nb_amf_pointer++;