From 002fa0050f767552ff22522a40716502c5b61d89 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 10 Mar 2025 18:15:34 +0100 Subject: [PATCH 01/25] 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 02/25] 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 03/25] 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 04/25] 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 05/25] 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 06/25] 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 07/25] 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 08/25] 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++; From 805d22aa3b7bad4494451bfe651f6955886b624e Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 28 May 2025 17:25:20 +0200 Subject: [PATCH 09/25] fixing band 50 (according to newer release), band 94 and adding new bands present in Rel.17 --- common/utils/nr/nr_common.c | 21 +++++++++++++++++---- openair1/PHY/INIT/nr_parms.c | 5 +++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 078ef027e8..5d98a99bb4 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -207,7 +207,7 @@ int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_ return -1; // not found } -// Table 5.2-1 NR operating bands in FR1 & FR2 (3GPP TS 38.101) +// Table 5.2-1 NR operating bands in FR1 & FR2 (3GPP TS 38.101) (Rel.17) // Table 5.4.2.3-1 Applicable NR-ARFCN per operating band in FR1 & FR2 (3GPP TS 38.101) // Notes: // - N_OFFs for bands from 80 to 89 and band 95 is referred to UL @@ -236,6 +236,7 @@ const nr_bandentry_t nr_bandtable[] = {{1, 1920000, 1980000, 2110000, 2170000, 2 {40, 2300000, 2400000, 2300000, 2400000, 20, 460000, 100}, {41, 2496000, 2690000, 2496000, 2690000, 3, 499200, 15}, {41, 2496000, 2690000, 2496000, 2690000, 6, 499200, 30}, + {46, 5150000, 5925000, 5150000, 5925000, 1, 743334, 15}, {47, 5855000, 5925000, 5855000, 5925000, 1, 790334, 15}, {48, 3550000, 3700000, 3550000, 3700000, 1, 636667, 15}, {48, 3550000, 3700000, 3550000, 3700000, 2, 636668, 30}, @@ -273,6 +274,11 @@ const nr_bandentry_t nr_bandtable[] = {{1, 1920000, 1980000, 2110000, 2170000, 2 {94, 880000, 915000, 1432000, 1517000, 20, 286400, 100}, {95, 2010000, 2025000, 000, 000, 20, 402000, 100}, {96, 5925000, 7125000, 5925000, 7125000, 1, 795000, 15}, + {100, 874400, 880000, 919400, 925000, 20, 174880, 100}, + {101, 1900000, 1910000, 1900000, 1910000, 20, 380000, 100}, + {102, 5925000, 6425000, 5925000, 6425000, 1, 795000, 15}, + {104, 6425000, 7125000, 6425000, 7125000, 1, 828334, 15}, + {104, 6425000, 7125000, 6425000, 7125000, 2, 828334, 30}, {254, 1610000, 1626500, 2483500, 2500000, 20, 496700, 100}, {254, 1610000, 1626500, 2483500, 2500000, 2, 496700, 10}, {255, 1626500, 1660500, 1525000, 1559000, 20, 305000, 100}, @@ -288,7 +294,7 @@ const nr_bandentry_t nr_bandtable[] = {{1, 1920000, 1980000, 2110000, 2170000, 2 {261, 27500040, 28350000, 27500040, 28350000, 1, 2070833, 60}, {261, 27500040, 28350000, 27500040, 28350000, 2, 2070833, 120}}; -// synchronization raster per band tables (Rel.15) +// synchronization raster per band tables (Rel.17) // (38.101-1 Table 5.4.3.3-1 and 38.101-2 Table 5.4.3.3-1) // band nb, sub-carrier spacing index, Range of gscn (First, Step size, Last) // clang-format off @@ -321,8 +327,9 @@ const sync_raster_t sync_raster[] = { {40, 1, 5762, 1, 5989}, {41, 0, 6246, 3, 6717}, {41, 1, 6252, 3, 6714}, + {46, 1, 8993, 1, 9530}, {48, 1, 7884, 1, 7982}, - {50, 0, 3584, 1, 3787}, + {50, 1, 3590, 1, 3781}, {51, 0, 3572, 1, 3574}, {53, 0, 6215, 1, 6232}, {53, 1, 6221, 1, 6226}, @@ -343,7 +350,13 @@ const sync_raster_t sync_raster[] = { {91, 0, 3572, 1, 3574}, {92, 0, 3584, 1, 3787}, {93, 0, 3572, 1, 3574}, - {94, 0, 3584, 1, 3587}, + {94, 0, 3584, 1, 3787}, + {96, 1, 9531, 1, 10363}, + {100, 0, 2303, 1, 2307}, + {101, 0, 4754, 1, 4768}, + {101, 1, 4760, 1, 4764}, + {102, 1, 9531, 1, 9877}, + {104, 1, 9882, 7, 10358}, {254, 0, 6215, 1, 6244}, {254, 1, 6218, 1, 6241}, {255, 0, 3818, 1, 3892}, diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index aa1eba0822..2ace21eab5 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -85,6 +85,11 @@ static const int nr_ssb_table[][3] = { {93, 15, nr_ssb_type_A}, {94, 15, nr_ssb_type_A}, {96, 30, nr_ssb_type_C}, + {100, 15, nr_ssb_type_A}, + {101, 15, nr_ssb_type_A}, + {101, 30, nr_ssb_type_C}, + {102, 30, nr_ssb_type_C}, + {104, 30, nr_ssb_type_C}, {254, 15, nr_ssb_type_A}, {254, 30, nr_ssb_type_C}, {255, 15, nr_ssb_type_A}, From 2fa337d8533172a2803d29f1a3b727309380cb51 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 25 Apr 2025 11:49:31 +0200 Subject: [PATCH 10/25] T bugfix: include size of 'length' to allocated memory The way allocation is done (granularity of 64KiB) makes a crash more difficult to achieve, but if a trace is exactly 64KiB, we miss 4 bytes in the realloc and then anything may happen. --- common/utils/T/tracer/extract_config.c | 4 ++-- common/utils/T/tracer/hacks/multi-rru-clean.c | 4 ++-- common/utils/T/tracer/multi.c | 4 ++-- common/utils/T/tracer/record.c | 4 ++-- common/utils/T/tracer/replay.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/utils/T/tracer/extract_config.c b/common/utils/T/tracer/extract_config.c index b908e60a83..73640cd3c1 100644 --- a/common/utils/T/tracer/extract_config.c +++ b/common/utils/T/tracer/extract_config.c @@ -46,8 +46,8 @@ int main(int n, char **v) /* read event from file */ if (fread(&length, 4, 1, in) != 1) break; - if (ebuf.omaxsize < length) { - ebuf.omaxsize = (length + 65535) & ~65535; + if (ebuf.omaxsize < length + 4) { + ebuf.omaxsize = (length + 4 + 65535) & ~65535; ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize); if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); } } diff --git a/common/utils/T/tracer/hacks/multi-rru-clean.c b/common/utils/T/tracer/hacks/multi-rru-clean.c index ec7c8f9d1b..1887c9bb2b 100644 --- a/common/utils/T/tracer/hacks/multi-rru-clean.c +++ b/common/utils/T/tracer/hacks/multi-rru-clean.c @@ -157,8 +157,8 @@ int main(int n, char **v) /* read event from file */ if (fread(&length, 4, 1, in) != 1) break; - if (ebuf.omaxsize < length) { - ebuf.omaxsize = (length + 65535) & ~65535; + if (ebuf.omaxsize < length + 4) { + ebuf.omaxsize = (length + 4 + 65535) & ~65535; ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize); if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); } } diff --git a/common/utils/T/tracer/multi.c b/common/utils/T/tracer/multi.c index 0b2e48ec7a..f10c520250 100644 --- a/common/utils/T/tracer/multi.c +++ b/common/utils/T/tracer/multi.c @@ -114,8 +114,8 @@ int read_tracee(int s, OBUF *ebuf, int *_type, int32_t *_length) int vpos = 0; if (fullread(s, &length, 4) == -1) return -1; - if (ebuf->omaxsize < length) { - ebuf->omaxsize = (length + 65535) & ~65535; + if (ebuf->omaxsize < length + 4) { + ebuf->omaxsize = (length + 4 + 65535) & ~65535; ebuf->obuf = realloc(ebuf->obuf, ebuf->omaxsize); if (ebuf->obuf == NULL) { printf("out of memory\n"); exit(1); } } diff --git a/common/utils/T/tracer/record.c b/common/utils/T/tracer/record.c index 9e3c4c41a3..d9f9f0837e 100644 --- a/common/utils/T/tracer/record.c +++ b/common/utils/T/tracer/record.c @@ -133,8 +133,8 @@ int main(int n, char **v) int vpos = 0; if (fullread(socket, &length, 4) == -1) goto read_error; - if (ebuf.omaxsize < length) { - ebuf.omaxsize = (length + 65535) & ~65535; + if (ebuf.omaxsize < length + 4) { + ebuf.omaxsize = (length + 4 + 65535) & ~65535; ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize); if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); } } diff --git a/common/utils/T/tracer/replay.c b/common/utils/T/tracer/replay.c index d9a505520a..10aec1588e 100644 --- a/common/utils/T/tracer/replay.c +++ b/common/utils/T/tracer/replay.c @@ -146,8 +146,8 @@ int main(int n, char **v) /* read event from file */ if (fread(&length, 4, 1, in) != 1) break; - if (ebuf.omaxsize < length) { - ebuf.omaxsize = (length + 65535) & ~65535; + if (ebuf.omaxsize < length + 4) { + ebuf.omaxsize = (length + 4 + 65535) & ~65535; ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize); if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); } } From 7a77ee2f432e367f919e9090492715bbb16d461f Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 25 Apr 2025 12:08:09 +0200 Subject: [PATCH 11/25] T: validate input data a bit more When data is generated by "normal" T tracers, it should be fine. But it might come from unknown sources and then content might be "strange". So let's validate input data a bit more. --- common/utils/T/tracer/event.c | 21 ++++++++++++++++++++- common/utils/T/tracer/multi.c | 2 ++ common/utils/T/tracer/record.c | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/common/utils/T/tracer/event.c b/common/utils/T/tracer/event.c index 61fb12dd2a..b7459ddcb8 100644 --- a/common/utils/T/tracer/event.c +++ b/common/utils/T/tracer/event.c @@ -24,9 +24,11 @@ event get_event(int socket, OBUF *event_buffer, void *database) again: if (fullread(socket, &length, 4) == -1) goto read_error; #ifdef T_SEND_TIME + if (length < sizeof(struct timespec)) goto error; if (fullread(socket, &t, sizeof(struct timespec)) == -1) goto read_error; length -= sizeof(struct timespec); #endif + if (length < sizeof(int)) goto error; if (fullread(socket, &type, sizeof(int)) == -1) goto read_error; length -= sizeof(int); if (event_buffer->omaxsize < length) { @@ -48,6 +50,9 @@ again: return new_event(type, length, event_buffer->obuf, database); #endif +error: + printf("error: bad data in get_event()\n"); + read_error: return (event){.type = -1}; } @@ -64,6 +69,9 @@ event new_event(int type, int length, char *buffer, void *database) int i; int offset; + /* arbitrary limit to 1GiB (to simplify size checks) */ + if (length < 0 || length > 1024 * 1024 * 1024) goto fatal; + #ifdef T_SEND_TIME e.sending_time = sending_time; #endif @@ -87,26 +95,33 @@ event new_event(int type, int length, char *buffer, void *database) for (i = 0; i < f.count; i++) { //e.e[i].offset = offset; if (!strcmp(f.type[i], "int")) { + if (offset + 4 > length) goto fatal; e.e[i].type = EVENT_INT; e.e[i].i = *(int *)(&buffer[offset]); offset += 4; } else if (!strcmp(f.type[i], "ulong")) { + if (offset + sizeof(unsigned long) > length) goto fatal; e.e[i].type = EVENT_ULONG; e.e[i].ul = *(unsigned long *)(&buffer[offset]); offset += sizeof(unsigned long); } else if (!strcmp(f.type[i], "float")) { + if (offset + sizeof(float) > length) goto fatal; e.e[i].type = EVENT_FLOAT; e.e[i].f = *(float *)(&buffer[offset]); offset += sizeof(float); } else if (!strcmp(f.type[i], "string")) { + if (offset + 1 > length) goto fatal; e.e[i].type = EVENT_STRING; e.e[i].s = &buffer[offset]; - while (buffer[offset]) offset++; + while (offset < length && buffer[offset]) offset++; + if (offset == length) goto fatal; offset++; } else if (!strcmp(f.type[i], "buffer")) { + if (offset + sizeof(int) > length) goto fatal; int len; e.e[i].type = EVENT_BUFFER; len = *(int *)(&buffer[offset]); + if (len <= 0 || offset + len + sizeof(int) > length) goto fatal; e.e[i].bsize = len; e.e[i].b = &buffer[offset+sizeof(int)]; offset += len+sizeof(int); @@ -119,4 +134,8 @@ event new_event(int type, int length, char *buffer, void *database) if (e.ecount==0) { printf("FORMAT not set in event %d\n", type); abort(); } return e; + +fatal: + printf("fatal: bad buffer in new_event\n"); + abort(); } diff --git a/common/utils/T/tracer/multi.c b/common/utils/T/tracer/multi.c index f10c520250..8e49ff43a1 100644 --- a/common/utils/T/tracer/multi.c +++ b/common/utils/T/tracer/multi.c @@ -123,10 +123,12 @@ int read_tracee(int s, OBUF *ebuf, int *_type, int32_t *_length) memcpy(v+vpos, &length, 4); vpos += 4; #ifdef T_SEND_TIME + if (length < sizeof(struct timespec)) return -1; if (fullread(s,v+vpos,sizeof(struct timespec))==-1) return -1; vpos += sizeof(struct timespec); length -= sizeof(struct timespec); #endif + if (length < sizeof(int)) return -1; if (fullread(s, &type, sizeof(int)) == -1) return -1; memcpy(v+vpos, &type, sizeof(int)); vpos += sizeof(int); diff --git a/common/utils/T/tracer/record.c b/common/utils/T/tracer/record.c index d9f9f0837e..f9d9dece64 100644 --- a/common/utils/T/tracer/record.c +++ b/common/utils/T/tracer/record.c @@ -142,10 +142,12 @@ int main(int n, char **v) memcpy(v+vpos, &length, 4); vpos += 4; #ifdef T_SEND_TIME + if (length < sizeof(struct timespec)) goto read_error; if (fullread(socket,v+vpos,sizeof(struct timespec))==-1) goto read_error; vpos += sizeof(struct timespec); length -= sizeof(struct timespec); #endif + if (length < sizeof(int)) goto read_error; if (fullread(socket, &type, sizeof(int)) == -1) goto read_error; memcpy(v+vpos, &type, sizeof(int)); vpos += sizeof(int); From ac01fcc1b4998c2b7ea6fa171fe8bf2d05ef7f1f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 2 Jun 2025 11:24:20 +0200 Subject: [PATCH 12/25] Move RLC-BearerConfig file to nr_rrc_config.c One of the next commits moves nr_rrc_config.c "down to" the MAC/DU. The BearerConfig functions are only used at the DU, so move them here in the corresponding file. --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 112 ---------------------------- openair2/RRC/NR/MESSAGES/asn1_msg.h | 6 -- openair2/RRC/NR/nr_rrc_config.c | 111 ++++++++++++++++++++++++++- openair2/RRC/NR/nr_rrc_config.h | 3 + 4 files changed, 113 insertions(+), 119 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 586e2e7628..6a7ee77b52 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -269,118 +269,6 @@ int do_RRCReject(uint8_t *const buffer) return (enc_rval.encoded + 7) / 8; } -NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, - long priority, - e_NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration bucketSizeDuration) -{ - NR_RLC_BearerConfig_t *rlc_BearerConfig = NULL; - rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); - rlc_BearerConfig->logicalChannelIdentity = channelId; - rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); - rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity; - rlc_BearerConfig->servedRadioBearer->choice.srb_Identity = channelId; - rlc_BearerConfig->reestablishRLC = NULL; - - NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); - rlc_Config->present = NR_RLC_Config_PR_am; - rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); - rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; - rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms35; - rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms0; - rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; - rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; - rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_infinity; - rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_infinity; - rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; - rlc_BearerConfig->rlc_Config = rlc_Config; - - NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); - logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); - logicalChannelConfig->ul_SpecificParameters->priority = priority; - logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; - logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = bucketSizeDuration; - - long *logicalChannelGroup = CALLOC(1, sizeof(long)); - *logicalChannelGroup = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; - logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); - *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; - rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; - - return rlc_BearerConfig; -} - -static void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config_pr) -{ - switch (rlc_config_pr) { - case NR_RLC_Config_PR_um_Bi_Directional: - // RLC UM Bi-directional Bearer configuration - LOG_I(RLC, "RLC UM Bi-directional Bearer configuration selected \n"); - rlc_Config->choice.um_Bi_Directional = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional)); - rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = - calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength)); - *rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; - rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = - calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength)); - *rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; - rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15; - break; - case NR_RLC_Config_PR_am: - // RLC AM Bearer configuration - rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); - rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength)); - *rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; - rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; - rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; - rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB500; - rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32; - rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength)); - *rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; - rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms15; - rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15; - break; - default: - AssertFatal(false, "RLC config type %d not handled\n", rlc_config_pr); - break; - } - rlc_Config->present = rlc_config_pr; -} - -NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority) -{ - NR_RLC_BearerConfig_t *rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); - rlc_BearerConfig->logicalChannelIdentity = lcChannelId; - rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); - rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity; - rlc_BearerConfig->servedRadioBearer->choice.drb_Identity = drbId; - rlc_BearerConfig->reestablishRLC = NULL; - - NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); - nr_drb_config(rlc_Config, rlc_conf); - rlc_BearerConfig->rlc_Config = rlc_Config; - - NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); - logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); - logicalChannelConfig->ul_SpecificParameters->priority = priority; - logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8; - logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100; - - long *logicalChannelGroup = CALLOC(1, sizeof(long)); - *logicalChannelGroup = 1; - logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; - logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); - *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; - rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; - - return rlc_BearerConfig; -} - /* returns a default radio bearer config suitable for NSA etc */ NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, int rb_id, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 344659afbb..afc9226b17 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -69,12 +69,6 @@ int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc); int do_RRCReject(uint8_t *const buffer); -NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig( - long channelId, - long priority, - e_NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration bucketSizeDuration); -NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority); - NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, int rb_id, e_NR_CipheringAlgorithm ciphering_algorithm, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index dfb5b9e231..27b9775237 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -35,7 +35,6 @@ #include #include "BIT_STRING.h" #include "NULL.h" -#include "RRC/NR/MESSAGES/asn1_msg.h" #include "RRC/NR/nr_rrc_proto.h" #include "SIMULATION/TOOLS/sim.h" #include "T.h" @@ -3348,6 +3347,116 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, return SpCellConfig; } +NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, long bucketSizeDuration) +{ + NR_RLC_BearerConfig_t *rlc_BearerConfig = NULL; + rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); + rlc_BearerConfig->logicalChannelIdentity = channelId; + rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); + rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity; + rlc_BearerConfig->servedRadioBearer->choice.srb_Identity = channelId; + rlc_BearerConfig->reestablishRLC = NULL; + + NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); + rlc_Config->present = NR_RLC_Config_PR_am; + rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); + rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; + rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms35; + rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms0; + rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; + rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; + rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_infinity; + rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_infinity; + rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; + rlc_BearerConfig->rlc_Config = rlc_Config; + + NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); + logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); + logicalChannelConfig->ul_SpecificParameters->priority = priority; + logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = bucketSizeDuration; + + long *logicalChannelGroup = CALLOC(1, sizeof(long)); + *logicalChannelGroup = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; + logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); + *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; + rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; + + return rlc_BearerConfig; +} + +static void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config_pr) +{ + switch (rlc_config_pr) { + case NR_RLC_Config_PR_um_Bi_Directional: + // RLC UM Bi-directional Bearer configuration + LOG_I(RLC, "RLC UM Bi-directional Bearer configuration selected \n"); + rlc_Config->choice.um_Bi_Directional = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional)); + rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = + calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength)); + *rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; + rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = + calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength)); + *rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; + rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15; + break; + case NR_RLC_Config_PR_am: + // RLC AM Bearer configuration + rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); + rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength)); + *rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; + rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; + rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; + rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB500; + rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32; + rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength)); + *rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; + rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms15; + rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15; + break; + default: + AssertFatal(false, "RLC config type %d not handled\n", rlc_config_pr); + break; + } + rlc_Config->present = rlc_config_pr; +} + +NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority) +{ + NR_RLC_BearerConfig_t *rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); + rlc_BearerConfig->logicalChannelIdentity = lcChannelId; + rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); + rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity; + rlc_BearerConfig->servedRadioBearer->choice.drb_Identity = drbId; + rlc_BearerConfig->reestablishRLC = NULL; + + NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); + nr_drb_config(rlc_Config, rlc_conf); + rlc_BearerConfig->rlc_Config = rlc_Config; + + NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); + logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); + logicalChannelConfig->ul_SpecificParameters->priority = priority; + logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8; + logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100; + + long *logicalChannelGroup = CALLOC(1, sizeof(long)); + *logicalChannelGroup = 1; + logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; + logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); + *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; + rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; + + return rlc_BearerConfig; +} + NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, const NR_ServingCellConfigCommon_t *scc, const NR_ServingCellConfig_t *servingcellconfigdedicated, diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index c4189dcb21..b9b074d377 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -116,4 +116,7 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc); +NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, long bucketSizeDuration); +NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority); + #endif From 8bf48f326aff5aa45ffa3fa27212f045b8fa82c4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 2 Jun 2025 11:25:47 +0200 Subject: [PATCH 13/25] Move NR_MAX_SUPPORTED_DL_LAYERS to where it is used --- openair2/RRC/NR/nr_rrc_config.c | 2 ++ openair2/RRC/NR/nr_rrc_proto.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 27b9775237..ecf361df91 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -57,6 +57,8 @@ #include "utils.h" #include "xer_encoder.h" +#define NR_MAX_SUPPORTED_DL_LAYERS 4 + #define PUCCH2_SIZE 8 const uint8_t slotsperframe[5] = {10, 20, 40, 80, 160}; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index c5627b6e55..4546f59723 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -39,8 +39,6 @@ #include "NR_CG-ConfigInfo.h" #include "NR_RRCReconfiguration.h" -#define NR_MAX_SUPPORTED_DL_LAYERS 4 - void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id); void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp); void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context); From c334ad7f7cbdd5d8db2c117c4124fda3eba60567 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 2 Jun 2025 11:30:31 +0200 Subject: [PATCH 14/25] Remove unused, add necessary headers --- openair2/RRC/NR/nr_rrc_config.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index ecf361df91..385dd5bc2d 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -29,15 +29,13 @@ */ #include "nr_rrc_config.h" + #include #include #include #include #include "BIT_STRING.h" #include "NULL.h" -#include "RRC/NR/nr_rrc_proto.h" -#include "SIMULATION/TOOLS/sim.h" -#include "T.h" #include "asn_SET_OF.h" #include "asn_codecs.h" #include "asn_internal.h" @@ -48,10 +46,11 @@ #include "constr_TYPE.h" #include "executables/softmodem-common.h" #include "oai_asn1.h" -#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair3/UTILS/conversions.h" + +#include "NR_MeasurementTimingConfiguration.h" #include "uper_decoder.h" #include "uper_encoder.h" #include "utils.h" From 4d755c9a1a5367061fbb68fbc621e62a35f2fe3a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 2 Jun 2025 11:39:33 +0200 Subject: [PATCH 15/25] Move nr_rrc_config.c to DU and rename nr_radio_config.c A number of radio-related RRC parameters, e.g., CellGroupConfig, "originate" at the DU and are sent to the CU for forwarding to the UE only. Similarly, there are additional parameters, e.g., RLC-BearerConfig (part of CellGroupConfig), that originate at the DU. Hence, the DU decides about these parameters, depending on the MAC state and capabilities. To clarify this, move the existing openair2/RRC/NR/nr_rrc_config.{c,h} => openair2/LAYER2/NR_MAC_gNB/nr_radio_config.{c,h} So that developers know that while those are RRC parameters, they originate at the DU. In other words, the CU/RRC is not supposed to use any of these functions in the RRC. Correspondingly, includes of this file have been cleaned up (and when they are not necessary at the MAC as well). --- CMakeLists.txt | 2 +- common/utils/telnetsrv/telnetsrv_o1.c | 2 +- doc/Doxyfile | 4 ++-- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair1/SIMULATION/NR_PHY/ulsim.c | 2 +- openair2/GNB_APP/gnb_config.c | 1 - openair2/LAYER2/NR_MAC_gNB/config.c | 1 - openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 1 + openair2/LAYER2/NR_MAC_gNB/main.c | 2 -- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- .../NR_MAC_gNB/nr_radio_config.c} | 11 +---------- .../NR_MAC_gNB/nr_radio_config.h} | 13 ++----------- openair2/RRC/NR/rrc_gNB_nsa.c | 1 - 13 files changed, 11 insertions(+), 33 deletions(-) rename openair2/{RRC/NR/nr_rrc_config.c => LAYER2/NR_MAC_gNB/nr_radio_config.c} (99%) rename openair2/{RRC/NR/nr_rrc_config.h => LAYER2/NR_MAC_gNB/nr_radio_config.h} (95%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b607056aa4..16dac5f2fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1147,7 +1147,6 @@ set(L2_NR_SRC ${NR_RRC_DIR}/rrc_gNB.c ${NR_RRC_DIR}/mac_rrc_dl_direct.c ${NR_RRC_DIR}/mac_rrc_dl_f1ap.c - ${NR_RRC_DIR}/nr_rrc_config.c ${NR_RRC_DIR}/rrc_gNB_nsa.c ${NR_RRC_DIR}/rrc_gNB_UE_context.c ${NR_RRC_DIR}/rrc_gNB_NGAP.c @@ -1230,6 +1229,7 @@ set (MAC_NR_SRC ${NR_GNB_MAC_DIR}/mac_rrc_dl_handler.c ${NR_GNB_MAC_DIR}/mac_rrc_ul_direct.c ${NR_GNB_MAC_DIR}/mac_rrc_ul_f1ap.c + ${NR_GNB_MAC_DIR}/nr_radio_config.c ) diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c index 7136f5a1b7..ac368885f6 100644 --- a/common/utils/telnetsrv/telnetsrv_o1.c +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -34,7 +34,7 @@ #include "openair2/RRC/NR/nr_rrc_defs.h" #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" -#include "openair2/RRC/NR/nr_rrc_config.h" +#include "openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c" #include "common/utils/nr/nr_common.h" diff --git a/doc/Doxyfile b/doc/Doxyfile index 6b0b390f05..f128e3eb88 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1677,6 +1677,7 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h \ +@CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h \ @@ -1687,6 +1688,7 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c \ +@CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/openair2_proc.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/RLC/rlc.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_UE/mac_tables.c \ @@ -1847,7 +1849,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_defs.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_if.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_direct.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_config.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl_direct.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_radio_bearers.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_NGAP.h \ @@ -1858,7 +1859,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_UE_context.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_e1ap.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_config.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_radio_bearers.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_NGAP.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl_f1ap.c \ diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index e36d50c6ad..6238c09a2e 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -37,6 +37,7 @@ #include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" #include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h" +#include "LAYER2/NR_MAC_gNB/nr_radio_config.h" #include "NR_BCCH-BCH-Message.h" #include "NR_BWP-Downlink.h" #include "NR_CellGroupConfig.h" @@ -61,7 +62,6 @@ #include "PHY/defs_nr_common.h" #include "PHY/impl_defs_nr.h" #include "PHY/phy_vars_nr_ue.h" -#include "RRC/NR/nr_rrc_config.h" #include "SCHED_NR/fapi_nr_l1.h" #include "SCHED_NR/sched_nr.h" #include "SCHED_NR_UE/defs.h" diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index da85ef0de4..4c12530f30 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -87,7 +87,7 @@ #include "openair1/SIMULATION/TOOLS/sim.h" #include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" -#include "openair2/RRC/NR/nr_rrc_config.h" +#include "openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h" #include "time_meas.h" #include "utils.h" diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 2c82a6eb6e..bc8a65b1e3 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -42,7 +42,6 @@ #include "PHY/INIT/nr_phy_init.h" #include "PHY/defs_gNB.h" #include "PHY/defs_nr_common.h" -#include "RRC/NR/nr_rrc_config.h" #include "RRC_nr_paramsvalues.h" #include "T.h" #include "asn_SEQUENCE_OF.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index aacae2bea1..43d48eeeeb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -44,7 +44,6 @@ #include "NR_BCCH-BCH-Message.h" #include "NR_ServingCellConfigCommon.h" #include "NR_MIB.h" -#include "RRC/NR/nr_rrc_config.h" #include "SCHED_NR/phy_frame_config_nr.h" #include "T.h" #include "asn_internal.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 9928c168c1..28c129cb58 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -22,6 +22,7 @@ #include "mac_rrc_dl_handler.h" #include "mac_proto.h" +#include "nr_radio_config.h" #include "openair2/F1AP/f1ap_ids.h" #include "openair2/F1AP/f1ap_common.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 3137ce0902..9c8e414f52 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -53,8 +53,6 @@ #include "NR_ServingCellConfig.h" #include "NR_ServingCellConfigCommon.h" #include "NR_TAG.h" -#include "RRC/NR/MESSAGES/asn1_msg.h" -#include "RRC/NR/nr_rrc_config.h" #include "assertions.h" #include "common/ngran_types.h" #include "common/ran_context.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 0b977de276..d97783604f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -74,7 +74,7 @@ #include "NR_BCCH-BCH-Message.h" #include "NR_CellGroupConfig.h" #include "NR_BCCH-DL-SCH-Message.h" -#include "openair2/RRC/NR/nr_rrc_config.h" +#include "nr_radio_config.h" /* PHY */ #include "time_meas.h" diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c similarity index 99% rename from openair2/RRC/NR/nr_rrc_config.c rename to openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 385dd5bc2d..fe4b138f49 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -19,16 +19,7 @@ * contact@openairinterface.org */ -/*! \file nr_rrc_config.c - * \brief rrc config for gNB - * \author Raymond Knopp, WEI-TAI CHEN - * \date 2018 - * \version 1.0 - * \company Eurecom, NTUST - * \email: raymond.knopp@eurecom.fr, kroempa@gmail.com - */ - -#include "nr_rrc_config.h" +#include "nr_radio_config.h" #include #include diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h similarity index 95% rename from openair2/RRC/NR/nr_rrc_config.h rename to openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h index b9b074d377..d5a7f8d40a 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h @@ -19,17 +19,8 @@ * contact@openairinterface.org */ -/*! \file nr_rrc_config.c - * \brief rrc config for gNB - * \author Raymond Knopp, WEI-TAI CHEN - * \date 2018 - * \version 1.0 - * \company Eurecom, NTUST - * \email: raymond.knopp@eurecom.fr, kroempa@gmail.com - */ - -#ifndef __NR_RRC_CONFIG_H__ -#define __NR_RRC_CONFIG_H__ +#ifndef __NR_MAC_RRC_CONFIG_H__ +#define __NR_MAC_RRC_CONFIG_H__ #include #include diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 120a400bbf..deabe38327 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -40,7 +40,6 @@ #include #include "MESSAGES/asn1_msg.h" #include "OCTET_STRING.h" -#include "RRC/NR/nr_rrc_config.h" #include "T.h" #include "asn_codecs.h" #include "asn_internal.h" From debad23a7e115ca4e4d80efa4b454e930e8b4fac Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 2 Jun 2025 17:27:21 +0200 Subject: [PATCH 16/25] Fix checking that amf_ip_address section is not set. The constructed setting path with prefix was invalid. --- openair2/GNB_APP/gnb_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 2c82a6eb6e..292f66c086 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -885,7 +885,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) verify_gnb_param_notset(gnbp, GNB_ENABLE_SDAP_IDX, GNB_CONFIG_STRING_ENABLE_SDAP); verify_gnb_param_notset(gnbp, GNB_DRBS, GNB_CONFIG_STRING_DRBS); - verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".", GNB_CONFIG_STRING_AMF_IP_ADDRESS); + verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".[0]", GNB_CONFIG_STRING_AMF_IP_ADDRESS); verify_section_notset(cfg, NULL, CONFIG_STRING_SECURITY); } // else nothing to be checked From e676d0d2cced033c3708416058ed7f9c09b56847 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Thu, 10 Apr 2025 16:32:40 +0200 Subject: [PATCH 17/25] Relax NR_UE_CAPABILITY_SLOT_RX_TO_TX asserts Relax the UEs requirements on k1/k2 value. --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 4 ++-- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 16aa7dcb8f..b6728df0dc 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -936,7 +936,7 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) { if (!get_FeedbackDisabled(mac->sc_info.downlinkHARQ_FeedbackDisabled_r17, dci->harq_pid.val)) { feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset; - AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), + AssertFatal(feedback_ti >= GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld).\n", feedback_ti, GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing)); @@ -1232,7 +1232,7 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, if (!get_FeedbackDisabled(mac->sc_info.downlinkHARQ_FeedbackDisabled_r17, dci->harq_pid.val)) { feedback_ti = pucch_Config->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0] + ntn_ue_koffset; - AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), + AssertFatal(feedback_ti >= GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld). Min feedback time set in config " "file (min_rxtxtime).\n", feedback_ti, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 2c94de6e70..7a44b0cf73 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1575,7 +1575,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, *slot_tx = (current_slot + k2 + delta) % slots_per_frame; *frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER; } else { - AssertFatal(k2 > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), + AssertFatal(k2 >= GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in " "gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", k2, From fc3e9f0efe8ce43c9582dc8809d7ce68657bf1ad Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 16 Apr 2025 17:41:02 +0200 Subject: [PATCH 18/25] UE TX time budget Measure the UEs TX time budget and warn if its violated. --- executables/nr-ue.c | 33 +++++++++++++++++++++++++++++++++ openair1/PHY/defs_nr_UE.h | 1 + 2 files changed, 34 insertions(+) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 1939c4175b..8849dad1b5 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -43,6 +43,7 @@ #include "position_interface.h" #include "nr_phy_common.h" #include "common/utils/time_manager/time_manager.h" +#include "log.h" /* * NR SLOT PROCESSING SEQUENCE @@ -545,6 +546,28 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx } } + if (!IS_SOFTMODEM_RFSIM) { + uint64_t deadline_us = rxtxD->absolute_deadline_us; + struct timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time)) { + LOG_E(PHY, "clock_gettime failed\n"); + } + uint64_t current_time_us = current_time.tv_sec * 1e6 + current_time.tv_nsec / 1e3; + if (current_time_us > deadline_us) { + static unsigned int deadline_warning_rate_limit = 0; + if (deadline_warning_rate_limit % 1000 == 0) { + LOG_W(PHY, + "Deadline missed for tx slot %d.%d (current time %lu us, deadline %lu us, missed by %lu)\n", + proc->frame_tx, + proc->nr_slot_tx, + current_time_us, + deadline_us, + current_time_us - deadline_us); + } + deadline_warning_rate_limit++; + } + } + openair0_timestamp writeTimestamp = proc->timestamp_tx; int writeBlockSize = rxtxD->writeBlockSize; // if writeBlockSize gets longer that slot size, fill with dummy @@ -1140,6 +1163,10 @@ void *UE_thread(void *arg) int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx); UEscopeCopy(UE, ueTimeDomainSamples, rxp[0], sizeof(c16_t), 1, readBlockSize, 0); AssertFatal(readBlockSize == tmp, ""); + struct timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time)) { + LOG_E(PHY, "clock_gettime failed\n"); + } if(slot_nr == (nb_slot_frame - 1)) { // read in first symbol of next frame and adjust for timing drift @@ -1162,6 +1189,11 @@ void *UE_thread(void *arg) const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, duration_rx_to_tx) - firstSymSamp - UE->N_TA_offset - timing_advance; + // Calculate TX deadline, approximately 1 symbol before the first sample should be written + const uint64_t samples_diff = writeTimestamp - rx_timestamp - fp->ofdm_symbol_size; + const float deadline_us = samples_diff / UE->rfdevice.openair0_cfg->sample_rate * 1e6; + const uint64_t absolute_deadline_us = current_time.tv_sec * 1e6 + current_time.tv_nsec / 1e3 + deadline_us; + // but use current UE->timing_advance value to compute writeBlockSize int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply; int new_timing_advance = UE->timing_advance; @@ -1204,6 +1236,7 @@ void *UE_thread(void *arg) curMsgTx->writeBlockSize = writeBlockSize; curMsgTx->proc.timestamp_tx = writeTimestamp; curMsgTx->UE = UE; + curMsgTx->absolute_deadline_us = absolute_deadline_us; int slot = curMsgTx->proc.nr_slot_tx; int slot_and_frame = slot + curMsgTx->proc.frame_tx * UE->frame_parms.slots_per_frame; diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index db8524eddd..9d8683481d 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -598,6 +598,7 @@ typedef struct nr_rxtx_thread_data_s { int writeBlockSize; nr_phy_data_t phy_data; dynamic_barrier_t* next_barrier; + uint64_t absolute_deadline_us; } nr_rxtx_thread_data_t; typedef struct LDPCDecode_ue_s { From 4ebe910363f94aa66b57308dd0d1657382e2962e Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 5 May 2025 15:06:36 +0200 Subject: [PATCH 19/25] Add extra cache for imscope record thread This should allow to capture UE time domain data after PDSCH decoding failure. --- openair1/PHY/TOOLS/imscope/imscope_record.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/TOOLS/imscope/imscope_record.cpp b/openair1/PHY/TOOLS/imscope/imscope_record.cpp index 6855e1b69d..a11b609054 100644 --- a/openair1/PHY/TOOLS/imscope/imscope_record.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope_record.cpp @@ -35,7 +35,7 @@ constexpr std::size_t hardware_destructive_interference_size = 64; #endif -#define NUM_CACHED_DATA 4 +#define NUM_CACHED_DATA 8 // Set maximum number of kilobytes written per recording session to 1GB. This is a safeguard against // recoding thread writing too many files and exhausting disk space. #define MAX_KBYTES_WRITTEN_PER_SESSION (1000 * 1000) From b58870d47c29f3bdec95eb5a1b73f461afd2acb6 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 5 May 2025 15:07:33 +0200 Subject: [PATCH 20/25] Add CSV iq export to Imscope Add CSV export button to imscope. --- openair1/PHY/TOOLS/imscope/imscope.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp index 48010e5883..9b5aeb0366 100644 --- a/openair1/PHY/TOOLS/imscope/imscope.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -248,6 +248,29 @@ class IQHist { if (!ss.str().empty()) { ImGui::Text("Data for %s", ss.str().c_str()); } + if (ImGui::Button("Save IQ")) { + std::stringstream ss; + ss << "iq_"; + if (iq_data->meta.frame != -1) { + ss << iq_data->meta.frame << "_"; + } + if (iq_data->meta.slot != -1) { + ss << iq_data->meta.slot << "_"; + } + ss << scope_id_to_string(static_cast(iq_data->scope_id)); + ss << ".csv"; + std::ofstream file(ss.str()); + if (file.is_open()) { + file << "real;imag\n"; + for (int i = 0; i < iq_data->len; i++) { + file << iq_data->real[i] << ";" << iq_data->imag[i] << "\n"; + } + file.close(); + std::cout << "Saved IQ to file: " << ss.str() << std::endl; + } else { + std::cerr << "Unable to open file"; + } + } ImGui::EndGroup(); } }; From 114ac4d1bb7d802bd95746699e3578aa60b9217b Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 5 May 2025 15:18:49 +0200 Subject: [PATCH 21/25] Add metadata to UE time domain samples scope Also fix the unintentional one symbol time delay. --- executables/nr-ue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 1939c4175b..0a40edf659 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -1138,7 +1138,8 @@ void *UE_thread(void *arg) const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply; openair0_timestamp rx_timestamp; int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx); - UEscopeCopy(UE, ueTimeDomainSamples, rxp[0], sizeof(c16_t), 1, readBlockSize, 0); + metadata meta = {.slot = curMsg.proc.nr_slot_rx, .frame = curMsg.proc.frame_rx}; + UEscopeCopyWithMetadata(UE, ueTimeDomainSamples, rxp[0] - firstSymSamp * sizeof(c16_t), sizeof(c16_t), 1, readBlockSize, 0, &meta); AssertFatal(readBlockSize == tmp, ""); if(slot_nr == (nb_slot_frame - 1)) { From 456fe094bcb4c8b91f600cf8434989e4c9b06f0a Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Fri, 9 May 2025 12:42:10 +0200 Subject: [PATCH 22/25] Add UE PDSCH ChanEst and pre-compensation IQ to imscope --- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 15 +++++++- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 10 +++++- openair1/PHY/TOOLS/imscope/imscope.cpp | 23 ++++++++++++ openair1/PHY/TOOLS/imscope/imscope_common.cpp | 15 ++++---- openair1/PHY/TOOLS/phy_scope_interface.h | 2 ++ openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 36 +++++++++++++++++-- 6 files changed, 90 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index a690c85ee3..d266d443e9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -323,7 +323,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT], int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT], int G, - uint32_t nvar) + uint32_t nvar, + pdsch_scope_req_t *scope_req) { const int nl = dlsch[0].Nl; const int matrixSz = ue->frame_parms.nb_antennas_rx * nl; @@ -463,6 +464,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, csi_res_bitmap, ue->chest_time); stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS); + if (scope_req->copy_chanest_to_scope) { + size_t size = sizeof(c16_t) * dlsch_config->number_rbs * NR_NB_SC_PER_RB; + int copy_index = symbol - dlsch_config->start_symbol; + int offset = copy_index * size; + UEscopeCopyUnsafe(ue, pdschChanEstimates, dl_ch_estimates_ext[0], size, offset, copy_index); + } if (meas_enabled) { LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: Pilot/Data extraction %5.2f \n", @@ -481,6 +488,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, nb_re_pdsch = (pilots == 1) ? ((config_type == NFAPI_NR_DMRS_TYPE1) ? nb_rb_pdsch * (12 - 6 * dlsch_config->n_dmrs_cdm_groups) : nb_rb_pdsch * (12 - 4 * dlsch_config->n_dmrs_cdm_groups)) : (nb_rb_pdsch * 12); + if (scope_req->copy_rxdataF_to_scope) { + size_t size = sizeof(c16_t) * nb_re_pdsch; + int copy_index = symbol - dlsch_config->start_symbol; + UEscopeCopyUnsafe(ue, pdschRxdataF, rxdataF_ext[0], size, scope_req->scope_rxdataF_offset, copy_index); + scope_req->scope_rxdataF_offset += size; + } //---------------------------------------------------------- //--------------------- Channel Scaling -------------------- //---------------------------------------------------------- diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 9c6e0c1454..8e266a57a3 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -41,6 +41,13 @@ #define NR_PUSCH_x 2 // UCI placeholder bit TS 38.212 V15.4.0 subclause 5.3.3.1 #define NR_PUSCH_y 3 // UCI placeholder bit +// Specifies the data that should be copied to the scope during PDSCH RX +typedef struct pdsch_scope_req_s { + bool copy_chanest_to_scope; + bool copy_rxdataF_to_scope; + size_t scope_rxdataF_offset; +} pdsch_scope_req_t; + // Functions below implement 36-211 and 36-212 /** @addtogroup _PHY_TRANSPORT_ @@ -314,7 +321,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT], int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT], int G, - uint32_t nvar); + uint32_t nvar, + pdsch_scope_req_t *scope_req); int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData); diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp index 9b5aeb0366..cce7a595f7 100644 --- a/openair1/PHY/TOOLS/imscope/imscope.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -455,6 +455,29 @@ void ShowUeScope(void *data_void_ptr, float t) } ImGui::End(); + if (ImGui::Begin("UE PDSCH Chan est")) { + static auto iq_data = new IQData(); + static auto iq_hist = new IQHist("PDSCH Chan est IQ"); + bool new_data = false; + if (iq_hist->ShouldReadData()) { + new_data = iq_data->TryCollect(&scope_array[pdschChanEstimates], t, iq_hist->GetEpsilon(), iq_procedure_timer); + } + iq_hist->Draw(iq_data, t, new_data); + } + ImGui::End(); + + if (ImGui::Begin("UE PDSCH IQ before compensation")) { + static auto iq_data = new IQData(); + static auto iq_hist = new IQHist("PDSCH IQ before compensation"); + bool new_data = false; + if (iq_hist->ShouldReadData()) { + new_data = iq_data->TryCollect(&scope_array[pdschRxdataF], t, iq_hist->GetEpsilon(), iq_procedure_timer); + } + iq_hist->Draw(iq_data, t, new_data); + } + ImGui::End(); + + if (ImGui::Begin("Time domain samples")) { static auto iq_data = new IQData(); // Issue with imgui deferring draw calls until the end of the frame - cases segfault if scatterplot has too many points diff --git a/openair1/PHY/TOOLS/imscope/imscope_common.cpp b/openair1/PHY/TOOLS/imscope/imscope_common.cpp index b1bdda0905..a480abbf5e 100644 --- a/openair1/PHY/TOOLS/imscope/imscope_common.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope_common.cpp @@ -131,12 +131,9 @@ void unlockScopeData(enum scopeDataType type) total_size += scope_data.data.data_copied_per_offset[i]; } if (total_size != (uint64_t)scope_data.data.scope_graph_data->dataSize) { - LOG_E(PHY, - "Scope is missing data - not all data that was expected was copied - possibly missed copyDataUnsafeWithOffset call. " - "scope = %s, total_size = %lu, dataSize = %d\n", - scope_id_to_string(type), - total_size, - scope_data.data.scope_graph_data->dataSize); + scope_data.data.scope_graph_data->dataSize = total_size; + scope_data.data.scope_graph_data->lineSz = + total_size / scope_data.data.scope_graph_data->elementSz / scope_data.data.scope_graph_data->colSz; } scope_data.data.scope_id = type; scope_data.is_data_ready = true; @@ -179,8 +176,12 @@ const char *scope_id_to_string(scopeDataType type) { return "ueTimeDomainSamplesBeforeSync"; case gNbTimeDomainSamples: return "gNbTimeDomainSamples"; + case pdschChanEstimates: + return "pdschChanEstimates"; + case pdschRxdataF: + return "pdschRxdataF"; default: - return "unknown type"; + return "unknown scope type"; } } diff --git a/openair1/PHY/TOOLS/phy_scope_interface.h b/openair1/PHY/TOOLS/phy_scope_interface.h index 181bf5985b..731a6250e5 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.h +++ b/openair1/PHY/TOOLS/phy_scope_interface.h @@ -77,6 +77,8 @@ enum scopeDataType { ueTimeDomainSamples, ueTimeDomainSamplesBeforeSync, gNbTimeDomainSamples, + pdschChanEstimates, + pdschRxdataF, EXTRA_SCOPE_TYPES }; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 8484a13101..976a5f8d88 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -606,6 +606,24 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, int32_t log2_maxh = 0; start_meas_nr_ue_phy(ue, RX_PDSCH_STATS); + pdsch_scope_req_t scope_req = { .copy_chanest_to_scope = false, + .copy_rxdataF_to_scope = false, + .scope_rxdataF_offset = 0 }; + if (UEScopeHasTryLock(ue)) { + metadata mt = {.frame = proc->frame_rx, .slot = proc->nr_slot_rx}; + scope_req.copy_chanest_to_scope = UETryLockScopeData(ue, + pdschChanEstimates, + sizeof(c16_t), + 1, + dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, + &mt); + scope_req.copy_rxdataF_to_scope = UETryLockScopeData(ue, + pdschRxdataF, + sizeof(c16_t), + 1, + dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, + &mt); + } for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) { bool first_symbol_flag = false; if (m == first_symbol_with_data) @@ -632,11 +650,25 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, ptrs_phase_per_slot, ptrs_re_per_slot, G, - nvar) - < 0) + nvar, + &scope_req) + < 0) { + if (scope_req.copy_chanest_to_scope) { + UEunlockScopeData(ue, pdschChanEstimates); + } + if (scope_req.copy_rxdataF_to_scope) { + UEunlockScopeData(ue, pdschRxdataF); + } return -1; + } } // CRNTI active stop_meas_nr_ue_phy(ue, RX_PDSCH_STATS); + if (scope_req.copy_chanest_to_scope) { + UEunlockScopeData(ue, pdschChanEstimates); + } + if (scope_req.copy_rxdataF_to_scope) { + UEunlockScopeData(ue, pdschRxdataF); + } free(toFree); free(toFree2); } From c52e2681c22019b4ae48f842d24fe2ef123d99a1 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Tue, 3 Jun 2025 13:25:01 +0200 Subject: [PATCH 23/25] CI: Use host network mode in NSA-B200 pipeline Following a power cycle of the CI machines in the NSA-B200 setup, the gNB machine encountered a networking issue. Although packets were observed leaving and returning to the host of gNB, they failed to reach the container. Debugging steps taken: - upgraded the gNB machine - reinstalled Docker - reviewed and verified IP rules and routing settings Setting the container to use host network mode resolved the issue. --- .../conf_files/gnb.nsa.band78.106prb.usrpb200.conf | 6 +++--- .../yaml_files/nsa_b200_gnb/docker-compose.yml | 13 +------------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf index 37eaa80b8c..bbe3168aa2 100644 --- a/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf @@ -169,10 +169,10 @@ gNBs = NETWORK_INTERFACES : { - GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.68.194"; - GNB_IPV4_ADDRESS_FOR_S1U = "192.168.68.194"; + GNB_IPV4_ADDRESS_FOR_S1_MME = "172.21.16.109"; + GNB_IPV4_ADDRESS_FOR_S1U = "172.21.16.109"; GNB_PORT_FOR_S1U = 2152; # Spec 2152 - GNB_IPV4_ADDRESS_FOR_X2C = "192.168.68.194"; + GNB_IPV4_ADDRESS_FOR_X2C = "172.21.16.109"; GNB_PORT_FOR_X2C = 36422; # Spec 36422 }; diff --git a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml index 3bd90a3fff..bb6576054e 100644 --- a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml @@ -9,6 +9,7 @@ services: - IPC_LOCK ulimits: core: -1 # for core dumps + network_mode: "host" environment: USE_B2XX: 'yes' USE_ADDITIONAL_OPTIONS: --nsa -E -q --RUs.[0].sdr_addrs serial=30C51D4 --continuous-tx --log_config.global_log_options level,nocolor,time,line_num,function @@ -16,9 +17,6 @@ services: - /dev/bus/usb/:/dev/bus/usb/ volumes: - ../../conf_files/gnb.nsa.band78.106prb.usrpb200.conf:/opt/oai-gnb/etc/gnb.conf - networks: - public_net: - ipv4_address: 192.168.68.194 #entrypoint: /bin/bash -c "sleep infinity" healthcheck: # pgrep does NOT work @@ -26,12 +24,3 @@ services: interval: 10s timeout: 5s retries: 5 - -networks: - public_net: - name: nsa-b200-gnb-net - ipam: - config: - - subnet: 192.168.68.192/26 - driver_opts: - com.docker.network.bridge.name: "nsa-gnb-net" From 85f3e62cafb72fec8eeeadff057f8a1f16cd47f7 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 19 May 2025 12:51:07 +0200 Subject: [PATCH 24/25] Fix data race in NR UE MSG3 scheduling Fixed a data race between DL processing of RAR and UL scheduler, which might result in dropping MSG3. It was possible that the UL scheduler for the UL slot which RAR indicates as MSG3 slot was already run by the time the RAR was decoded. Therefore when DCI for RAR is decoded, assume worst case and halt the earliest corresponding UL scheduler call until RAR is decoded solving the data race. This also in turn halts all later scheduling due to sequential nature of the UL scheduler calls. --- executables/nr-ue.c | 3 ++- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 2 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 19 +++++++++++++++++-- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 4 ++++ openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 9 +++++++++ openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 17 +---------------- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 4 +--- openair2/RRC/NR/nr_rrc_config.c | 3 +-- 8 files changed, 36 insertions(+), 25 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 1939c4175b..7201191cb7 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -728,7 +728,8 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, } sampleShift = pbch_pdcch_processing(UE, proc, phy_data); - if (phy_data->dlsch[0].active && phy_data->dlsch[0].rnti_type == TYPE_C_RNTI_) { + if (phy_data->dlsch[0].active + && (phy_data->dlsch[0].rnti_type == TYPE_C_RNTI_ || phy_data->dlsch[0].rnti_type == TYPE_RA_RNTI_)) { // indicate to tx thread to wait for DLSCH decoding if (phy_data->dlsch[0].dlsch_config.k1_feedback) { // if feedback is 0 there is no HARQ associated with this DLSCH const int ack_nack_slot = (proc->nr_slot_rx + phy_data->dlsch[0].dlsch_config.k1_feedback) % fp->slots_per_frame; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 8484a13101..5681a738b5 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -815,7 +815,7 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, } // DLSCH decoding finished! don't wait anymore in Tx process, we know if we should answer ACK/NACK PUCCH - if (dlsch[0].rnti_type == TYPE_C_RNTI_ && dlsch[0].dlsch_config.k1_feedback) { + if ((dlsch[0].rnti_type == TYPE_C_RNTI_ || dlsch[0].rnti_type == TYPE_RA_RNTI_) && dlsch[0].dlsch_config.k1_feedback) { const int ack_nack_slot_and_frame = (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame; dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]); diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 594992c1cb..b435e9e265 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -368,8 +368,7 @@ NR_tda_info_t get_ul_tda_info(const NR_UE_UL_BWP_t *ul_bwp, NR_PUSCH_TimeDomainResourceAllocationList_t *tdalist = get_ul_tdalist(ul_bwp, controlResourceSetId, ss_type, rnti_type); // Definition of value j in Table 6.1.2.1.1-4 of 38.214 int scs = ul_bwp->scs; - AssertFatal(scs >= 0 && scs < 5, "Subcarrier spacing indicatior %d invalid value\n", scs); - int j = scs == 0 ? 1 : scs; + int j = get_j_for_k2(scs); if (tdalist) { tda_info.valid_tda = tda_index < tdalist->list.count; if (!tda_info.valid_tda) { @@ -5129,3 +5128,19 @@ int nr_get_prach_or_ul_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, return mu; } + +int get_delta_for_k2(int mu) +{ + // 38.214 Table 6.1.2.1.1-5: Definition of value Δ + int delta_table[] = {2, 3, 4, 6, 24, 48}; + AssertFatal(mu >= 0 && mu < sizeofArray(delta_table), "Invalid numerology %d\n", mu); + return delta_table[mu]; +} + +int get_j_for_k2(int mu) +{ + // 38.214 Table 6.1.2.1.1-4: Definition of value j + int j_table[] = {1, 1, 2, 3, 11, 21}; + AssertFatal(mu >= 0 && mu < sizeofArray(j_table), "Invalid numerology %d\n", mu); + return j_table[mu]; +} diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 2607d8f587..84284f0c48 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -318,4 +318,8 @@ int get_nrofHARQ_ProcessesForPUSCH(const NR_UE_ServingCell_Info_t *sc_info); int nr_get_prach_or_ul_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, const NR_RACH_ConfigCommon_t *rach_ConfigCommon, const int ul_mu); +int get_delta_for_k2(int mu); + +int get_j_for_k2(int mu); + #endif diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 16aa7dcb8f..a1deff0444 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -933,6 +933,15 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing); uint16_t feedback_ti = 0; + if (rnti_type == TYPE_RA_RNTI_) { + // RA-RNTI indicates RAR. Ensure we can decode RAR before the earliest UL scheduler call + // that can process the MSG3. Also assume that RAR is sent in the same slot as DCI (k0 == 0) + // This is not perfect as the MSG3 might end up being scheduled later, so we could be + // halting the UL scheduler for a longer time than necessary. + feedback_ti = max(1 + GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), + get_delta_for_k2(mac->current_UL_BWP->scs) + get_j_for_k2(mac->current_UL_BWP->scs)); + } + if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) { if (!get_FeedbackDisabled(mac->sc_info.downlinkHARQ_FeedbackDisabled_r17, dci->harq_pid.val)) { feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 2c94de6e70..016570108a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1547,22 +1547,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, if (is_Msg3) { - switch (mu) { - case 0: - delta = 2; - break; - case 1: - delta = 3; - break; - case 2: - delta = 4; - break; - case 3: - delta = 6; - break; - default: - AssertFatal(1 == 0, "Invalid numerology %i\n", mu); - } + delta = get_delta_for_k2(mu); AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to " diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 63700d2a72..e67a30e67a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -58,8 +58,6 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, int fh); static void nr_fill_rar(uint8_t Mod_idP, NR_UE_info_t *UE, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu); -static const uint8_t DELTA[4] = {2, 3, 4, 6}; - static const float ssb_per_rach_occasion[8] = {0.125, 0.25, 0.5, 1, 2, 4, 8}; static int16_t ssb_index_from_prach(module_id_t module_idP, @@ -1566,7 +1564,7 @@ static void nr_generate_Msg2(module_id_t module_idP, const NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; bool ret = get_feasible_msg3_tda(scc, - DELTA[ul_bwp->scs], + get_delta_for_k2(ul_bwp->scs), ul_bwp->tdaList_Common, frameP, slotP, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index dfb5b9e231..338ce21fc7 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -1066,7 +1066,6 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) AssertFatal(tda->list.count == 0, "already have pusch_TimeDomainAllocationList members\n"); const int k2 = min_fb_delay; - uint8_t DELTA[4]= {2,3,4,6}; // Delta parameter for Msg3 int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; struct NR_SetupRelease_PUSCH_ConfigCommon *pusch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon; @@ -1099,7 +1098,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) int tdd_period_idx = get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon); int nb_periods_per_frame = get_nb_periods_per_frame(tdd_period_idx); int nb_slots_per_period = ((1 << mu) * 10) / nb_periods_per_frame; - int k2_msg3 = nb_slots_per_period - DELTA[mu]; + int k2_msg3 = nb_slots_per_period - get_delta_for_k2(mu); struct NR_PUSCH_TimeDomainResourceAllocation *puschTdrAllocMsg3 = set_TimeDomainResourceAllocation(k2_msg3, 3, ul_symb); if (*puschTdrAllocMsg3->k2 < min_fb_delay) *puschTdrAllocMsg3->k2 += nb_slots_per_period; From 72c29248a3c9eb5817978fc6a582e7f1ceb923a2 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Tue, 3 Jun 2025 17:03:17 +0200 Subject: [PATCH 25/25] remove dead globals --- executables/nr-uesoftmodem.c | 3 --- openair1/PHY/CODING/nrLDPC_extern.h | 5 ----- 2 files changed, 8 deletions(-) diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 3106f823b3..f1e94e9e55 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -368,9 +368,6 @@ void start_oai_nrue_threads() int NB_UE_INST = 1; configmodule_interface_t *uniqCfg = NULL; - -// A global var to reduce the changes size -ldpc_interface_t ldpc_interface = {0}, ldpc_interface_offload = {0}; nrLDPC_coding_interface_t nrLDPC_coding_interface = {0}; int main(int argc, char **argv) diff --git a/openair1/PHY/CODING/nrLDPC_extern.h b/openair1/PHY/CODING/nrLDPC_extern.h index a0e10db155..7c4287d3f1 100644 --- a/openair1/PHY/CODING/nrLDPC_extern.h +++ b/openair1/PHY/CODING/nrLDPC_extern.h @@ -31,15 +31,10 @@ typedef struct ldpc_interface_s { LDPC_encoderfunc_t *LDPCencoder; } ldpc_interface_t; -// Global var to limit the rework of the dirty legacy code -extern ldpc_interface_t ldpc_interface, ldpc_interface_offload, ldpc_interface_segment; - /* functions to load the LDPC shared lib, implemented in openair1/PHY/CODING/nrLDPC_load.c */ int load_LDPClib(char *version, ldpc_interface_t *); int free_LDPClib(ldpc_interface_t *ldpc_interface); -LDPC_initfunc_t LDPCinit; -LDPC_shutdownfunc_t LDPCshutdown; LDPC_decoderfunc_t LDPCdecoder; LDPC_encoderfunc_t LDPCencoder;