From 5d9f7b41c1c8a85c96f44fa8abe0f9a7aec60132 Mon Sep 17 00:00:00 2001 From: Rakesh BB Date: Wed, 4 Mar 2026 06:37:45 +0000 Subject: [PATCH 1/4] XNAP: add logging support and update ASN.1 runtime sources - Add XNAP component to the logging framework in log.h - Introduce LEGACY_XNAP log message definitions (INFO, ERROR, WARNING, DEBUG, TRACE) in T_messages.txt for tracing and debugging XNAP procedures - Update xnap_R16.2.0.cmake formatting for consistency - Add missing ASN.1 runtime sources required by XNAP (e.g. asn_codecs_prim_xer.c, BIT_STRING_print.c, BIT_STRING_rfill.c, etc.) --- common/utils/LOG/log.h | 1 + common/utils/T/T_messages.txt | 21 +++ .../XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake | 124 +++++++++++++++++- 3 files changed, 141 insertions(+), 5 deletions(-) diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h index 837c6897a6..b8ccedffbe 100644 --- a/common/utils/LOG/log.h +++ b/common/utils/LOG/log.h @@ -162,6 +162,7 @@ static const char *const flag_name[] = {FOREACH_FLAG(FLAG_TEXT) ""}; COMP_DEF(USIM, log) \ COMP_DEF(F1U, ) \ COMP_DEF(X2AP, ) \ + COMP_DEF(XNAP, ) \ COMP_DEF(M2AP, ) \ COMP_DEF(M3AP, ) \ COMP_DEF(NGAP, ) \ diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 818b30b7d0..432ad30262 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -628,6 +628,27 @@ ID = LEGACY_X2AP_TRACE GROUP = ALL:LEGACY_X2AP:LEGACY_GROUP_TRACE:LEGACY FORMAT = string,log +ID = LEGACY_XNAP_INFO + DESC = XNAP legacy logs - info level + GROUP = ALL:LEGACY_XNAP:LEGACY_GROUP_INFO:LEGACY + FORMAT = string,log +ID = LEGACY_XNAP_ERROR + DESC = XNAP legacy logs - error level + GROUP = ALL:LEGACY_XNAP:LEGACY_GROUP_ERROR:LEGACY + FORMAT = string,log +ID = LEGACY_XNAP_WARNING + DESC = XNAP legacy logs - warning level + GROUP = ALL:LEGACY_XNAP:LEGACY_GROUP_WARNING:LEGACY + FORMAT = string,log +ID = LEGACY_XNAP_DEBUG + DESC = XNAP legacy logs - debug level + GROUP = ALL:LEGACY_XNAP:LEGACY_GROUP_DEBUG:LEGACY + FORMAT = string,log +ID = LEGACY_XNAP_TRACE + DESC = XNAP legacy logs - trace level + GROUP = ALL:LEGACY_XNAP:LEGACY_GROUP_TRACE:LEGACY + FORMAT = string,log + ID = LEGACY_M2AP_INFO DESC = M2AP legacy logs - info level GROUP = ALL:LEGACY_M2AP:LEGACY_GROUP_INFO:LEGACY diff --git a/openair2/XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake b/openair2/XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake index cb0c762983..4a46649449 100644 --- a/openair2/XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake +++ b/openair2/XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake @@ -1,4 +1,4 @@ -set( XNAP_GRAMMAR ASN1/xnap_R16.2.0.asn) +set(XNAP_GRAMMAR ASN1/xnap_R16.2.0.asn) set(xnap_source ANY.c @@ -9,6 +9,7 @@ set(xnap_source asn_application.c asn_bit_data.c asn_codecs_prim.c + asn_codecs_prim_xer.c asn_internal.c asn_random_fill.c asn_SEQUENCE_OF.c @@ -16,20 +17,73 @@ set(xnap_source ber_tlv_length.c ber_tlv_tag.c BIT_STRING.c + BIT_STRING_print.c + BIT_STRING_rfill.c + BIT_STRING_uper.c + BIT_STRING_xer.c constraints.c constr_CHOICE.c + constr_CHOICE_aper.c + constr_CHOICE_rfill.c + constr_CHOICE_print.c + constr_CHOICE_uper.c + constr_CHOICE_xer.c constr_SEQUENCE.c + constr_SEQUENCE_aper.c constr_SEQUENCE_OF.c + constr_SEQUENCE_OF_aper.c + constr_SEQUENCE_OF_uper.c + constr_SEQUENCE_OF_xer.c + constr_SEQUENCE_print.c + constr_SEQUENCE_rfill.c + constr_SEQUENCE_uper.c + constr_SEQUENCE_xer.c constr_SET_OF.c + constr_SET_OF_aper.c + constr_SET_OF_print.c + constr_SET_OF_rfill.c + constr_SET_OF_uper.c + constr_SET_OF_xer.c constr_TYPE.c INTEGER.c + INTEGER_aper.c + INTEGER_print.c + INTEGER_rfill.c + INTEGER_uper.c + INTEGER_xer.c Makefile.am.libasncodec NativeEnumerated.c + NativeEnumerated_aper.c + NativeEnumerated_uper.c + NativeEnumerated_xer.c NativeInteger.c + NativeInteger_aper.c + NativeInteger_print.c + NativeInteger_rfill.c + NativeInteger_uper.c + NativeInteger_xer.c NULL.c + NULL_aper.c + NULL_print.c + NULL_rfill.c + NULL_uper.c + NULL_xer.c OBJECT_IDENTIFIER.c + OBJECT_IDENTIFIER_print.c + OBJECT_IDENTIFIER_rfill.c + OBJECT_IDENTIFIER_xer.c OCTET_STRING.c + OCTET_STRING_aper.c + OCTET_STRING_print.c + OCTET_STRING_rfill.c + OCTET_STRING_uper.c + OCTET_STRING_xer.c OPEN_TYPE.c + OPEN_TYPE_aper.c + OPEN_TYPE_uper.c + OPEN_TYPE_xer.c + per_opentype.c + per_encoder.c VisibleString.c xer_decoder.c xer_encoder.c @@ -819,14 +873,22 @@ set(xnap_source XNAP_XnUAddressIndication.c XNAP_XnUAddressInfoperPDUSession-Item.c XNAP_XnUAddressInfoperPDUSession-List.c + uper_encoder.c + uper_opentype.c + uper_support.c ) set(xnap_headers ANY.h + aper_decoder.h + aper_encoder.h + aper_opentype.h + aper_support.h asn_application.h asn_bit_data.h asn_codecs.h asn_codecs_prim.h + asn_codecs_prim_xer.h asn_internal.h asn_ioc.h asn_random_fill.h @@ -836,23 +898,72 @@ set(xnap_headers ber_tlv_length.h ber_tlv_tag.h BIT_STRING.h + BIT_STRING_print.h + BIT_STRING_rfill.h + BIT_STRING_uper.h + BIT_STRING_xer.h constraints.h constr_CHOICE.h + constr_CHOICE_aper.h + constr_CHOICE_print.h + constr_CHOICE_rfill.h + constr_CHOICE_uper.h + constr_CHOICE_xer.h constr_SEQUENCE.h + constr_SEQUENCE_aper.h constr_SEQUENCE_OF.h + constr_SEQUENCE_OF_aper.h + constr_SEQUENCE_OF_uper.h + constr_SEQUENCE_OF_xer.h + constr_SEQUENCE_print.h + constr_SEQUENCE_rfill.h + constr_SEQUENCE_uper.h + constr_SEQUENCE_xer.h constr_SET_OF.h + constr_SET_OF_aper.h + constr_SET_OF_print.h + constr_SET_OF_rfill.h + constr_SET_OF_uper.h + constr_SET_OF_xer.h constr_TYPE.h INTEGER.h + INTEGER_aper.h + INTEGER_print.h + INTEGER_rfill.h + INTEGER_uper.h + INTEGER_xer.h NativeEnumerated.h + NativeEnumerated_aper.h + NativeEnumerated_uper.h + NativeEnumerated_xer.h NativeInteger.h + NativeInteger_aper.h + NativeInteger_print.h + NativeInteger_rfill.h + NativeInteger_xer.h + NativeInteger_uper.h NULL.h + NULL_aper.h + NULL_print.h + NULL_rfill.h + NULL_uper.h + NULL_xer.h OBJECT_IDENTIFIER.h + OBJECT_IDENTIFIER_print.h + OBJECT_IDENTIFIER_rfill.h + OBJECT_IDENTIFIER_xer.h OCTET_STRING.h + OCTET_STRING_aper.h + OCTET_STRING_print.h + OCTET_STRING_rfill.h + OCTET_STRING_uper.h + OCTET_STRING_xer.h OPEN_TYPE.h - aper_decoder.h - aper_encoder.h - aper_opentype.h - aper_support.h + OPEN_TYPE_aper.h + OPEN_TYPE_uper.h + OPEN_TYPE_xer.h + per_encoder.h + per_opentype.h VisibleString.h xer_decoder.h xer_encoder.h @@ -1643,5 +1754,8 @@ set(xnap_headers XNAP_XnUAddressIndication.h XNAP_XnUAddressInfoperPDUSession-Item.h XNAP_XnUAddressInfoperPDUSession-List.h + uper_encoder.h + uper_opentype.h + uper_support.h ) From 08b454bd15b5841a983a0553f65aa87a209d0593 Mon Sep 17 00:00:00 2001 From: Rakesh BB Date: Wed, 4 Mar 2026 07:04:32 +0000 Subject: [PATCH 2/4] XNAP: Introduce XnAP library framework and add encode/decode, unit test for Xn Setup Request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add initial XnAP library structure under openair2/XNAP/lib - Implement common XnAP helper utilities (xnap_lib_common) - Add gNB interface management module for Xn Setup procedures - Introduce XnAP message type definitions in xnap_messages_types.h - Integrate XnAP library into build system (CMakeLists.txt) - Add standalone XnAP library unit test (xnap_lib_test) - Implement encoder, decoder + test for Xn Setup Request Xn Setup Request (3GPP TS 38.423v16.2.0 §9.1.3.1) - Global NG-RAN Node ID (M) - TAI Support List (M) - AMF Region Information (M) - Extend conversions.h with MACRO_BIT_STRING_TO_GNB_ID utility Co-authored-by: Sreeshma Shiv --- CMakeLists.txt | 11 + openair2/COMMON/xnap_messages_types.h | 65 +++++ openair2/XNAP/CMakeLists.txt | 12 +- openair2/XNAP/lib/CMakeLists.txt | 10 + .../XNAP/lib/xnap_gNB_interface_management.c | 246 ++++++++++++++++++ .../XNAP/lib/xnap_gNB_interface_management.h | 37 +++ openair2/XNAP/lib/xnap_lib_common.c | 61 +++++ openair2/XNAP/lib/xnap_lib_common.h | 60 +++++ openair2/XNAP/lib/xnap_lib_includes.h | 42 +++ openair2/XNAP/tests/CMakeLists.txt | 9 + openair2/XNAP/tests/xnap_lib_test.c | 176 +++++++++++++ openair3/UTILS/conversions.h | 10 + 12 files changed, 734 insertions(+), 5 deletions(-) create mode 100644 openair2/COMMON/xnap_messages_types.h create mode 100644 openair2/XNAP/lib/CMakeLists.txt create mode 100644 openair2/XNAP/lib/xnap_gNB_interface_management.c create mode 100644 openair2/XNAP/lib/xnap_gNB_interface_management.h create mode 100644 openair2/XNAP/lib/xnap_lib_common.c create mode 100644 openair2/XNAP/lib/xnap_lib_common.h create mode 100644 openair2/XNAP/lib/xnap_lib_includes.h create mode 100644 openair2/XNAP/tests/CMakeLists.txt create mode 100644 openair2/XNAP/tests/xnap_lib_test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index b8a1b3a082..1cb3e09736 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -517,6 +517,17 @@ add_library(x2ap target_link_libraries(x2ap PUBLIC asn1_x2ap) target_link_libraries(x2ap PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) +#XNAP +############## +set(XNAP_DIR ${OPENAIR2_DIR}/XNAP) +add_library(xnap + ${XNAP_DIR}/xnap_common.c + ) +target_include_directories(xnap PUBLIC XNAP_DIR) +target_link_libraries(xnap PUBLIC asn1_xnap) +target_link_libraries(xnap PRIVATE nr_rrc xnap_lib) +target_include_directories(xnap PRIVATE ${XNAP_DIR}/lib) + # F1AP ############## set(F1AP_DIR ${OPENAIR2_DIR}/F1AP) diff --git a/openair2/COMMON/xnap_messages_types.h b/openair2/COMMON/xnap_messages_types.h new file mode 100644 index 0000000000..1080e5fb1b --- /dev/null +++ b/openair2/COMMON/xnap_messages_types.h @@ -0,0 +1,65 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef XNAP_MESSAGES_TYPES_H_ +#define XNAP_MESSAGES_TYPES_H_ + +#include "common/5g_platform_types.h" + +typedef struct { + // PLMN Identity + plmn_id_t plmn; + // Number of supported S-NSSAIs + uint16_t num_nssai; + // List of supported S-NSSAIs + nssai_t *nssai; +} xnap_plmn_support_t; + +typedef struct { + // Tracking Area Code + uint32_t tac; + // Number of supported PLMNs + uint8_t num_plmn; + // List of supported PLMNs + xnap_plmn_support_t *plmn_support; +} xnap_tai_support_t; + +typedef struct { + // PLMN Identity + plmn_id_t plmn; + // AMF Region Identifier + uint8_t amf_region_id; +} xnap_amf_region_info_t; + +/* 3GPP TS 38.423 9.1.3.1 – Xn Setup Request */ +typedef struct { + // Global NG-RAN Node ID (gNB_id+plmn) (M) + uint32_t gNB_id; + plmn_id_t plmn; + // TAI Support List (M) + uint16_t num_tai; + xnap_tai_support_t *tai_support; + // AMF Region Information (M) + uint8_t num_amf_regions; + xnap_amf_region_info_t *amf_region_info; +} xnap_setup_req_t; + +#endif /* XNAP_MESSAGES_TYPES_H_ */ diff --git a/openair2/XNAP/CMakeLists.txt b/openair2/XNAP/CMakeLists.txt index d003732d8a..10576f8403 100644 --- a/openair2/XNAP/CMakeLists.txt +++ b/openair2/XNAP/CMakeLists.txt @@ -1,7 +1,9 @@ +add_subdirectory(lib) add_subdirectory(MESSAGES) -add_library(xnap xnap_common.c) -target_link_libraries(xnap - PUBLIC asn1_xnap - PRIVATE nr_rrc) -target_include_directories(xnap PUBLIC ${CMAKE_CURRENT_DIR}) + +if(ENABLE_TESTS) + add_subdirectory(tests) +endif() + + diff --git a/openair2/XNAP/lib/CMakeLists.txt b/openair2/XNAP/lib/CMakeLists.txt new file mode 100644 index 0000000000..5e4d5124b0 --- /dev/null +++ b/openair2/XNAP/lib/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(xnap_lib OBJECT + xnap_lib_common.c + xnap_gNB_interface_management.c +) +target_link_libraries(xnap_lib PRIVATE asn1_xnap ds) + +if(ENABLE_TESTS) + target_compile_definitions(xnap_lib PRIVATE ENABLE_TESTS) +endif() + diff --git a/openair2/XNAP/lib/xnap_gNB_interface_management.c b/openair2/XNAP/lib/xnap_gNB_interface_management.c new file mode 100644 index 0000000000..b374580851 --- /dev/null +++ b/openair2/XNAP/lib/xnap_gNB_interface_management.c @@ -0,0 +1,246 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* + * \brief xnap interface handler procedures for gNB + */ + +#include "xnap_gNB_interface_management.h" +#include "xnap_lib_common.h" +#include "xnap_lib_includes.h" + +/** + * @brief XnAP Setup Request encoding + */ +XNAP_XnAP_PDU_t *encode_xn_setup_request(const xnap_setup_req_t *msg) +{ + XNAP_XnAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* PDU type */ + pdu->present = XNAP_XnAP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, initMsg); + initMsg->procedureCode = XNAP_ProcedureCode_id_xnSetup; + initMsg->criticality = XNAP_Criticality_reject; + initMsg->value.present = XNAP_InitiatingMessage__value_PR_XnSetupRequest; + + XNAP_XnSetupRequest_t *out = &initMsg->value.choice.XnSetupRequest; + + /* Global NG-RAN Node ID (M) */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_XnSetupRequest_IEs_t, ieC1); + ieC1->id = XNAP_ProtocolIE_ID_id_GlobalNG_RAN_node_ID; + ieC1->criticality = XNAP_Criticality_reject; + ieC1->value.present = XNAP_XnSetupRequest_IEs__value_PR_GlobalNG_RANNode_ID; + + XNAP_GlobalNG_RANNode_ID_t *global = &ieC1->value.choice.GlobalNG_RANNode_ID; + global->present = XNAP_GlobalNG_RANNode_ID_PR_gNB; + asn1cCalloc(global->choice.gNB, gnb); + + MCC_MNC_TO_PLMNID(msg->plmn.mcc, msg->plmn.mnc, msg->plmn.mnc_digit_length, &gnb->plmn_id); + gnb->gnb_id.present = XNAP_GNB_ID_Choice_PR_gnb_ID; + MACRO_GNB_ID_TO_BIT_STRING(msg->gNB_id, &gnb->gnb_id.choice.gnb_ID); + + /* TAI Support List (M) */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_XnSetupRequest_IEs_t, ieC2); + ieC2->id = XNAP_ProtocolIE_ID_id_TAISupport_list; + ieC2->criticality = XNAP_Criticality_reject; + ieC2->value.present = XNAP_XnSetupRequest_IEs__value_PR_TAISupport_List; + + for (int i = 0; i < msg->num_tai; i++) { + asn1cSequenceAdd(ieC2->value.choice.TAISupport_List.list, XNAP_TAISupport_Item_t, taiItem); + INT24_TO_OCTET_STRING(msg->tai_support[i].tac, &taiItem->tac); + + for (int j = 0; j < msg->tai_support[i].num_plmn; j++) { + const xnap_plmn_support_t *plmn = &msg->tai_support[i].plmn_support[j]; + asn1cSequenceAdd(taiItem->broadcastPLMNs.list, XNAP_BroadcastPLMNinTAISupport_Item_t, plmnItem); + MCC_MNC_TO_PLMNID(plmn->plmn.mcc, plmn->plmn.mnc, plmn->plmn.mnc_digit_length, &plmnItem->plmn_id); + + for (int k = 0; k < plmn->num_nssai; k++) { + asn1cSequenceAdd(plmnItem->tAISliceSupport_List.list, XNAP_S_NSSAI_t, nssai); + INT8_TO_OCTET_STRING(plmn->nssai[k].sst, &nssai->sst); + if (plmn->nssai[k].sd) { asn1cCalloc(nssai->sd, sd); INT24_TO_OCTET_STRING(plmn->nssai[k].sd, sd); } + } + } + } + + /* AMF Region Information (M) */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_XnSetupRequest_IEs_t, ieC3); + ieC3->id = XNAP_ProtocolIE_ID_id_AMF_Region_Information; + ieC3->criticality = XNAP_Criticality_reject; + ieC3->value.present = XNAP_XnSetupRequest_IEs__value_PR_AMF_Region_Information; + + for (int i = 0; i < msg->num_amf_regions; i++) { + const xnap_amf_region_info_t *amf = &msg->amf_region_info[i]; + asn1cSequenceAdd(ieC3->value.choice.AMF_Region_Information.list, XNAP_GlobalAMF_Region_Information_t, amfItem); + MCC_MNC_TO_PLMNID(amf->plmn.mcc, amf->plmn.mnc, amf->plmn.mnc_digit_length, &amfItem->plmn_ID); + INT8_TO_OCTET_STRING(amf->amf_region_id, &amfItem->amf_region_id); + } + + return pdu; +} + +/** + * @brief XnAP Setup Request decoding + */ +bool decode_xn_setup_request(xnap_setup_req_t *out, const XNAP_XnAP_PDU_t *pdu) +{ + /* Check presence of message type */ + _EQ_CHECK_INT(pdu->present, XNAP_XnAP_PDU_PR_initiatingMessage); + AssertError(pdu->choice.initiatingMessage != NULL, return false, "pdu->choice.initiatingMessage is NULL"); + _EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, XNAP_ProcedureCode_id_xnSetup); + _EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, XNAP_InitiatingMessage__value_PR_XnSetupRequest); + /* XnSetupRequest container */ + XNAP_XnSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.XnSetupRequest; + + XNAP_XnSetupRequest_IEs_t *ie; + /* Check presence of mandatory IEs */ + XNAP_LIB_FIND_IE(XNAP_XnSetupRequest_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_GlobalNG_RAN_node_ID, true); + XNAP_LIB_FIND_IE(XNAP_XnSetupRequest_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_TAISupport_list, true); + XNAP_LIB_FIND_IE(XNAP_XnSetupRequest_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_AMF_Region_Information, true); + + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + AssertError(in->protocolIEs.list.array[i] != NULL, return false, "protocolIEs.list.array[i] is NULL"); + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case XNAP_ProtocolIE_ID_id_GlobalNG_RAN_node_ID: { + /* Global NG-RAN Node ID (M) */ + _EQ_CHECK_INT(ie->value.present, XNAP_XnSetupRequest_IEs__value_PR_GlobalNG_RANNode_ID); + XNAP_GlobalNG_RANNode_ID_t *global_id = &ie->value.choice.GlobalNG_RANNode_ID; + AssertError(global_id->present == XNAP_GlobalNG_RANNode_ID_PR_gNB, return false, "Only gNB supported"); + AssertError(global_id->choice.gNB != NULL, return false, "gNB is NULL"); + /* Decode PLMN */ + PLMNID_TO_MCC_MNC(&global_id->choice.gNB->plmn_id, + out->plmn.mcc, + out->plmn.mnc, + out->plmn.mnc_digit_length); + /* Decode gNB ID */ + AssertError(global_id->choice.gNB->gnb_id.present == XNAP_GNB_ID_Choice_PR_gnb_ID, return false, "Unsupported gNB ID choice"); + MACRO_BIT_STRING_TO_GNB_ID(&global_id->choice.gNB->gnb_id.choice.gnb_ID, out->gNB_id); + } break; + + case XNAP_ProtocolIE_ID_id_TAISupport_list: { + /* TAI Support List (M) */ + _EQ_CHECK_INT(ie->value.present, XNAP_XnSetupRequest_IEs__value_PR_TAISupport_List); + int tai_count = ie->value.choice.TAISupport_List.list.count; + out->num_tai = tai_count; + out->tai_support = calloc_or_fail(tai_count, sizeof(*out->tai_support)); + for (int m = 0; m < tai_count; m++) { + XNAP_TAISupport_Item_t *tai_item = ie->value.choice.TAISupport_List.list.array[m]; + /* TAC */ + OCTET_STRING_TO_INT24(&tai_item->tac, out->tai_support[m].tac); + /* PLMN list */ + out->tai_support[m].num_plmn = tai_item->broadcastPLMNs.list.count; + out->tai_support[m].plmn_support = calloc_or_fail(out->tai_support[m].num_plmn, sizeof(*out->tai_support[m].plmn_support)); + for (int j = 0; j < out->tai_support[m].num_plmn; j++) { + XNAP_BroadcastPLMNinTAISupport_Item_t *plmn_item = tai_item->broadcastPLMNs.list.array[j]; + xnap_plmn_support_t *plmn = &out->tai_support[m].plmn_support[j]; + PLMNID_TO_MCC_MNC(&plmn_item->plmn_id, + plmn->plmn.mcc, + plmn->plmn.mnc, + plmn->plmn.mnc_digit_length); + /* NSSAI */ + plmn->num_nssai = plmn_item->tAISliceSupport_List.list.count; + plmn->nssai = calloc_or_fail(plmn->num_nssai, sizeof(*plmn->nssai)); + for (int k = 0; k < plmn->num_nssai; k++) { + OCTET_STRING_TO_INT8(&plmn_item->tAISliceSupport_List.list.array[k]->sst, plmn->nssai[k].sst); + if (plmn_item->tAISliceSupport_List.list.array[k]->sd) { + OCTET_STRING_TO_INT24(plmn_item->tAISliceSupport_List.list.array[k]->sd, plmn->nssai[k].sd); + } + } + } + } + } break; + + case XNAP_ProtocolIE_ID_id_AMF_Region_Information: { + /* AMF Region Information (M) */ + _EQ_CHECK_INT(ie->value.present, XNAP_XnSetupRequest_IEs__value_PR_AMF_Region_Information); + out->num_amf_regions = ie->value.choice.AMF_Region_Information.list.count; + out->amf_region_info = calloc_or_fail(out->num_amf_regions, sizeof(*out->amf_region_info)); + for (int a = 0; a < out->num_amf_regions; a++) { + XNAP_GlobalAMF_Region_Information_t *amf = ie->value.choice.AMF_Region_Information.list.array[a]; + PLMNID_TO_MCC_MNC(&amf->plmn_ID, + out->amf_region_info[a].plmn.mcc, + out->amf_region_info[a].plmn.mnc, + out->amf_region_info[a].plmn.mnc_digit_length); + OCTET_STRING_TO_INT8(&amf->amf_region_id, out->amf_region_info[a].amf_region_id); + } + } break; + + default: + AssertError(0, return false, "Unknown XnAP IE id %ld\n", ie->id); + break; + } + } + return true; +} + +/** + * @brief XnAP Setup Request main equality check + */ +bool eq_xnap_setup_request(const xnap_setup_req_t *a, const xnap_setup_req_t *b) +{ + _EQ_CHECK_UINT32(a->gNB_id, b->gNB_id); + if (!eq_xnap_plmn(&a->plmn, &b->plmn)) return false; + + _EQ_CHECK_INT(a->num_tai, b->num_tai); + for (int i = 0; i < a->num_tai; i++) { + if (!eq_xnap_tai_support(&a->tai_support[i], &b->tai_support[i])) + return false; + } + + _EQ_CHECK_INT(a->num_amf_regions, b->num_amf_regions); + for (int i = 0; i < a->num_amf_regions; i++) { + if (!eq_xnap_plmn(&a->amf_region_info[i].plmn, &b->amf_region_info[i].plmn)) + return false; + _EQ_CHECK_INT(a->amf_region_info[i].amf_region_id, b->amf_region_info[i].amf_region_id); + } + + return true; +} + +static void free_xnap_plmn_support(xnap_plmn_support_t *plmn_support, uint8_t num_plmn) +{ + if (!plmn_support) return; + for (int i = 0; i < num_plmn; i++) { + free(plmn_support[i].nssai); + } + free(plmn_support); +} + +static void free_xnap_tai_support(xnap_tai_support_t *tai_support, uint16_t num_tai) +{ + if (!tai_support) return; + for (int i = 0; i < num_tai; i++) { + free_xnap_plmn_support(tai_support[i].plmn_support, + tai_support[i].num_plmn); + } + free(tai_support); +} + +/** + * @brief XnAP Setup Request memory management + */ +void free_xnap_setup_request(const xnap_setup_req_t *msg) +{ + DevAssert(msg != NULL); + free_xnap_tai_support(msg->tai_support, msg->num_tai); + free(msg->amf_region_info); +} diff --git a/openair2/XNAP/lib/xnap_gNB_interface_management.h b/openair2/XNAP/lib/xnap_gNB_interface_management.h new file mode 100644 index 0000000000..a4e65d6e00 --- /dev/null +++ b/openair2/XNAP/lib/xnap_gNB_interface_management.h @@ -0,0 +1,37 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef XNAP_GNB_INTERFACE_MANAGEMENT_H_ +#define XNAP_GNB_INTERFACE_MANAGEMENT_H_ + +#include +#include "xnap_messages_types.h" +typedef struct XNAP_XnAP_PDU XNAP_XnAP_PDU_t; + +XNAP_XnAP_PDU_t *encode_xn_setup_request(const xnap_setup_req_t *req); + +bool decode_xn_setup_request(xnap_setup_req_t *req, const XNAP_XnAP_PDU_t *pdu); + +bool eq_xnap_setup_request(const xnap_setup_req_t *a, const xnap_setup_req_t *b); + +void free_xnap_setup_request(const xnap_setup_req_t *msg); + +#endif /* XNAP_GNB_INTERFACE_MANAGEMENT_H_ */ diff --git a/openair2/XNAP/lib/xnap_lib_common.c b/openair2/XNAP/lib/xnap_lib_common.c new file mode 100644 index 0000000000..9c6a09c80c --- /dev/null +++ b/openair2/XNAP/lib/xnap_lib_common.c @@ -0,0 +1,61 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "xnap_lib_common.h" +#include "common/utils/assertions.h" +#include "common/utils/utils.h" + +bool eq_xnap_plmn(const plmn_id_t *a, const plmn_id_t *b) +{ + _EQ_CHECK_INT(a->mcc, b->mcc); + _EQ_CHECK_INT(a->mnc, b->mnc); + _EQ_CHECK_INT(a->mnc_digit_length, b->mnc_digit_length); + return true; +} + +bool eq_xnap_snssai(const nssai_t *a, const nssai_t *b) +{ + _EQ_CHECK_INT(a->sst, b->sst); + _EQ_CHECK_UINT32(a->sd, b->sd); + return true; +} + +bool eq_xnap_plmn_support(const xnap_plmn_support_t *a, const xnap_plmn_support_t *b) +{ + if (!eq_xnap_plmn(&a->plmn, &b->plmn)) return false; + _EQ_CHECK_INT(a->num_nssai, b->num_nssai); + for (int i = 0; i < a->num_nssai; i++) { + if (!eq_xnap_snssai(&a->nssai[i], &b->nssai[i])) + return false; + } + return true; +} + +bool eq_xnap_tai_support(const xnap_tai_support_t *a, const xnap_tai_support_t *b) +{ + _EQ_CHECK_UINT32(a->tac, b->tac); + _EQ_CHECK_INT(a->num_plmn, b->num_plmn); + for (int i = 0; i < a->num_plmn; i++) { + if (!eq_xnap_plmn_support(&a->plmn_support[i], &b->plmn_support[i])) + return false; + } + return true; +} diff --git a/openair2/XNAP/lib/xnap_lib_common.h b/openair2/XNAP/lib/xnap_lib_common.h new file mode 100644 index 0000000000..cde0accd88 --- /dev/null +++ b/openair2/XNAP/lib/xnap_lib_common.h @@ -0,0 +1,60 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef XNAP_LIB_COMMON_H_ +#define XNAP_LIB_COMMON_H_ + +#include +#include +#include +#include +#include +#include "openair3/UTILS/conversions.h" +#include "common/utils/oai_asn1.h" +#include "common/utils/utils.h" +#include "common/utils/eq_check.h" +#include "xnap_messages_types.h" +#include "xnap_lib_includes.h" + +/* macro to look up XnAP IE. If mandatory and not found, macro will print + * descriptive debug message to stderr and force exit in calling function */ +#define XNAP_LIB_FIND_IE(IE_TYPE, ie, IE_LIST, IE_ID, mandatory) \ + do { \ + ie = NULL; \ + for (IE_TYPE **ptr = (IE_LIST)->array; ptr < &(IE_LIST)->array[(IE_LIST)->count]; ptr++) { \ + if ((*ptr)->id == IE_ID) { \ + ie = *ptr; \ + break; \ + } \ + } \ + if ((mandatory) && (ie == NULL)) { \ + fprintf(stderr, "%s(): could not find XnAP IE " #IE_ID " of type " #IE_TYPE "\n", __func__); \ + return false; \ + } \ + } while (0) + +/* Function Prototypes */ +bool eq_xnap_plmn(const plmn_id_t *a, const plmn_id_t *b); +bool eq_xnap_snssai(const nssai_t *a, const nssai_t *b); +bool eq_xnap_tai_support(const xnap_tai_support_t *a, const xnap_tai_support_t *b); +bool eq_xnap_plmn_support(const xnap_plmn_support_t *a, const xnap_plmn_support_t *b); + +#endif /* XNAP_LIB_COMMON_H_ */ diff --git a/openair2/XNAP/lib/xnap_lib_includes.h b/openair2/XNAP/lib/xnap_lib_includes.h new file mode 100644 index 0000000000..a67919413a --- /dev/null +++ b/openair2/XNAP/lib/xnap_lib_includes.h @@ -0,0 +1,42 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* + * \brief XnAP ASN.1 message definitions generated from specifications + */ + +#ifndef XNAP_LIB_INCLUDES_H +#define XNAP_LIB_INCLUDES_H + +#include "XNAP_XnAP-PDU.h" +#include "XNAP_ProtocolIE-Field.h" +#include "XNAP_InitiatingMessage.h" + +#include "XNAP_GlobalgNB-ID.h" +#include "XNAP_GlobalNG-RANNode-ID.h" +#include "XNAP_GlobalAMF-Region-Information.h" +#include "XNAP_TAISupport-Item.h" +#include "XNAP_S-NSSAI.h" +#include "XNAP_BroadcastPLMNinTAISupport-Item.h" + + +#endif // XNAP_LIB_INCLUDES_H + diff --git a/openair2/XNAP/tests/CMakeLists.txt b/openair2/XNAP/tests/CMakeLists.txt new file mode 100644 index 0000000000..7c6875b887 --- /dev/null +++ b/openair2/XNAP/tests/CMakeLists.txt @@ -0,0 +1,9 @@ +add_executable(xnap_lib_test xnap_lib_test.c) +add_dependencies(tests xnap_lib_test) +add_test(NAME xnap_lib_test COMMAND xnap_lib_test) +target_link_libraries(xnap_lib_test PRIVATE xnap_lib ds LOG) +target_link_libraries(xnap_lib_test PRIVATE asn1_xnap) +target_include_directories(xnap_lib_test PRIVATE + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/openair2/XNAP/tests/xnap_lib_test.c b/openair2/XNAP/tests/xnap_lib_test.c new file mode 100644 index 0000000000..c17f6b4967 --- /dev/null +++ b/openair2/XNAP/tests/xnap_lib_test.c @@ -0,0 +1,176 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* + * \brief Test functions for XnAP encoding/decoding library + */ + +#include +#include +#include +#include +#include "common/utils/assertions.h" +#include "common/utils/utils.h" +#include "xnap_messages_types.h" +#include "openair2/XNAP/lib/xnap_lib_common.h" +#include "openair2/XNAP/lib/xnap_gNB_interface_management.h" + +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + printf("detected error at %s:%d:%s: %s\n", file, line, function, s); + abort(); +} + +/* Helper for ASN.1 Encoding/Decoding loop */ +static XNAP_XnAP_PDU_t *xnap_encode_decode(const XNAP_XnAP_PDU_t *enc_pdu) +{ + //xer_fprint(stdout, &asn_DEF_XNAP_XnAP_PDU, enc_pdu); + DevAssert(enc_pdu != NULL); + char errbuf[1024]; + size_t errlen = sizeof(errbuf); + int ret = asn_check_constraints(&asn_DEF_XNAP_XnAP_PDU, enc_pdu, errbuf, &errlen); + AssertFatal(ret == 0, "asn_check_constraints() failed: %s\n", errbuf); + + uint8_t msgbuf[16384]; + // 1. Encode + asn_enc_rval_t enc = aper_encode_to_buffer(&asn_DEF_XNAP_XnAP_PDU, NULL, enc_pdu, msgbuf, sizeof(msgbuf)); + AssertFatal(enc.encoded > 0, "aper_encode_to_buffer() failed\n"); + + // 2. Decode + XNAP_XnAP_PDU_t *dec_pdu = NULL; + asn_codec_ctx_t st = {.max_stack_size = 100 * 1000}; + asn_dec_rval_t dec = aper_decode(&st, &asn_DEF_XNAP_XnAP_PDU, (void **)&dec_pdu, msgbuf, enc.encoded, 0, 0); + AssertFatal(dec.code == RC_OK, "aper_decode() failed\n"); + + //xer_fprint(stdout, &asn_DEF_XNAP_XnAP_PDU, dec_pdu); + + return dec_pdu; +} + +static void xnap_msg_free(XNAP_XnAP_PDU_t *pdu) +{ + ASN_STRUCT_FREE(asn_DEF_XNAP_XnAP_PDU, pdu); +} + +/** + * 1. Xn Setup Request + */ +static void test_xn_setup_request(void) +{ + /* ---------- Common PLMNs ---------- */ + plmn_id_t plmn0 = { .mcc = 208, .mnc = 95, .mnc_digit_length = 2 }; + plmn_id_t plmn1 = { .mcc = 208, .mnc = 93, .mnc_digit_length = 2 }; + + /* ---------- TAI support (2) ---------- */ + xnap_tai_support_t *tai_support = calloc_or_fail(2, sizeof(*tai_support)); + + /* ================= TAI 0 ================= */ + tai_support[0].tac = 1; + tai_support[0].num_plmn = 2; + tai_support[0].plmn_support = calloc_or_fail(2, sizeof(*tai_support[0].plmn_support)); + + /* ---- TAI 0 / PLMN 0 ---- */ + tai_support[0].plmn_support[0].plmn = plmn0; + tai_support[0].plmn_support[0].num_nssai = 3; + tai_support[0].plmn_support[0].nssai = calloc_or_fail(3, sizeof(nssai_t)); + + tai_support[0].plmn_support[0].nssai[0] = (nssai_t){ .sst = 1, .sd = 0x010203 }; + tai_support[0].plmn_support[0].nssai[1] = (nssai_t){ .sst = 1, .sd = 0x010204 }; + tai_support[0].plmn_support[0].nssai[2] = (nssai_t){ .sst = 1, .sd = 0x010205 }; + + /* ---- TAI 0 / PLMN 1 ---- */ + tai_support[0].plmn_support[1].plmn = plmn1; + tai_support[0].plmn_support[1].num_nssai = 3; + tai_support[0].plmn_support[1].nssai = calloc_or_fail(3, sizeof(nssai_t)); + + tai_support[0].plmn_support[1].nssai[0] = (nssai_t){ .sst = 2, .sd = 0x020203 }; + tai_support[0].plmn_support[1].nssai[1] = (nssai_t){ .sst = 2, .sd = 0x020204 }; + tai_support[0].plmn_support[1].nssai[2] = (nssai_t){ .sst = 2, .sd = 0x020205 }; + + /* ================= TAI 1 ================= */ + tai_support[1].tac = 2; + tai_support[1].num_plmn = 2; + tai_support[1].plmn_support = calloc_or_fail(2, sizeof(*tai_support[1].plmn_support)); + + /* ---- TAI 1 / PLMN 0 ---- */ + tai_support[1].plmn_support[0].plmn = plmn0; + tai_support[1].plmn_support[0].num_nssai = 3; + tai_support[1].plmn_support[0].nssai = calloc_or_fail(3, sizeof(nssai_t)); + + tai_support[1].plmn_support[0].nssai[0] = (nssai_t){ .sst = 3, .sd = 0x030203 }; + tai_support[1].plmn_support[0].nssai[1] = (nssai_t){ .sst = 3, .sd = 0x030204 }; + tai_support[1].plmn_support[0].nssai[2] = (nssai_t){ .sst = 3, .sd = 0x030205 }; + + /* ---- TAI 1 / PLMN 1 ---- */ + tai_support[1].plmn_support[1].plmn = plmn1; + tai_support[1].plmn_support[1].num_nssai = 3; + tai_support[1].plmn_support[1].nssai = calloc_or_fail(3, sizeof(nssai_t)); + + tai_support[1].plmn_support[1].nssai[0] = (nssai_t){ .sst = 4, .sd = 0x040203 }; + tai_support[1].plmn_support[1].nssai[1] = (nssai_t){ .sst = 4, .sd = 0x040204 }; + tai_support[1].plmn_support[1].nssai[2] = (nssai_t){ .sst = 4, .sd = 0x040205 }; + + /* ---------- AMF region info (2) ---------- */ + xnap_amf_region_info_t *amf_region_info = calloc_or_fail(2, sizeof(*amf_region_info)); + + amf_region_info[0].plmn = plmn0; + amf_region_info[0].amf_region_id = 1; + + amf_region_info[1].plmn = plmn1; + amf_region_info[1].amf_region_id = 2; + + /* ---------- create message ---------- */ + xnap_setup_req_t orig = { + .gNB_id = 0xABCDE, + .plmn = plmn0, + .num_tai = 2, + .tai_support = tai_support, + .num_amf_regions = 2, + .amf_region_info = amf_region_info, + }; + /* ---------- encode ---------- */ + XNAP_XnAP_PDU_t *xnenc = encode_xn_setup_request(&orig); + XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc); + xnap_msg_free(xnenc); + + /* ---------- decode ---------- */ + xnap_setup_req_t decoded = {0}; + bool ret = decode_xn_setup_request(&decoded, xndec); + AssertFatal(ret, "decode_xn_setup_request failed"); + xnap_msg_free(xndec); + + /* ---------- equality ---------- */ + ret = eq_xnap_setup_request(&orig, &decoded); + AssertFatal(ret, "Xn Setup Req mismatch\n"); + free_xnap_setup_request(&decoded); + free_xnap_setup_request(&orig); + printf("%s() successful \n", __func__); +} + +int main() { + printf("Starting XnAP Library Unit Tests...\n"); + + /* Xn Interface Testing */ + test_xn_setup_request(); + + printf("All XnAP tests passed!\n"); + return 0; +} diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h index b545d8eb8d..4715bf653b 100644 --- a/openair3/UTILS/conversions.h +++ b/openair3/UTILS/conversions.h @@ -497,6 +497,16 @@ do { \ (bITsTRING)->bits_unused = 4; \ } while(0) +#define MACRO_BIT_STRING_TO_GNB_ID(bITsTRING, oUT) \ +do { \ + uint8_t *_buf = (bITsTRING)->buf; \ + (oUT) = \ + ((uint32_t)_buf[0] << 20) | \ + ((uint32_t)_buf[1] << 12) | \ + ((uint32_t)_buf[2] << 4) | \ + (((uint32_t)_buf[3] & 0xF0) >> 4); \ +} while (0) + /* TS 36.413 v10.9.0 section 9.2.1.38: * E-UTRAN CGI/Cell Identity * The leftmost bits of the Cell From 467015e005c3a469450dbb2bf9e7e5e7b8885535 Mon Sep 17 00:00:00 2001 From: Rakesh BB Date: Sat, 31 Jan 2026 10:16:26 +0000 Subject: [PATCH 3/4] XNAP: add encode/decode and unit test for Xn Setup Response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Xn Setup Response message type definitions - Implement encoder and decoder for Xn Setup Response Xn Setup Response (3GPP TS 38.423v16.2.0 §9.1.3.2) - Global NG-RAN Node ID (M) - TAI Support List (M) - Add equality check and memory management helpers - Extend XNAP library unit tests to cover Setup Response --- openair2/COMMON/xnap_messages_types.h | 10 ++ .../XNAP/lib/xnap_gNB_interface_management.c | 159 ++++++++++++++++++ .../XNAP/lib/xnap_gNB_interface_management.h | 4 + openair2/XNAP/lib/xnap_lib_includes.h | 2 +- openair2/XNAP/tests/xnap_lib_test.c | 85 ++++++++++ 5 files changed, 259 insertions(+), 1 deletion(-) diff --git a/openair2/COMMON/xnap_messages_types.h b/openair2/COMMON/xnap_messages_types.h index 1080e5fb1b..fc360d2558 100644 --- a/openair2/COMMON/xnap_messages_types.h +++ b/openair2/COMMON/xnap_messages_types.h @@ -62,4 +62,14 @@ typedef struct { xnap_amf_region_info_t *amf_region_info; } xnap_setup_req_t; +/* 3GPP TS 38.423 9.1.3.2 – Xn Setup Response */ +typedef struct { + // Global NG-RAN Node ID (gNB_id+plmn) (M) + uint32_t gNB_id; + plmn_id_t plmn; + // TAI Support List (M) + uint16_t num_tai; + xnap_tai_support_t *tai_support; +} xnap_setup_resp_t; + #endif /* XNAP_MESSAGES_TYPES_H_ */ diff --git a/openair2/XNAP/lib/xnap_gNB_interface_management.c b/openair2/XNAP/lib/xnap_gNB_interface_management.c index b374580851..409ce7b967 100644 --- a/openair2/XNAP/lib/xnap_gNB_interface_management.c +++ b/openair2/XNAP/lib/xnap_gNB_interface_management.c @@ -244,3 +244,162 @@ void free_xnap_setup_request(const xnap_setup_req_t *msg) free_xnap_tai_support(msg->tai_support, msg->num_tai); free(msg->amf_region_info); } + +/** + * @brief XnAP Setup Response encoding + */ +XNAP_XnAP_PDU_t *encode_xn_setup_response(const xnap_setup_resp_t *resp) +{ + XNAP_XnAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* PDU type */ + pdu->present = XNAP_XnAP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, succMsg); + succMsg->procedureCode = XNAP_ProcedureCode_id_xnSetup; + succMsg->criticality = XNAP_Criticality_reject; + succMsg->value.present = XNAP_SuccessfulOutcome__value_PR_XnSetupResponse; + + XNAP_XnSetupResponse_t *out = &succMsg->value.choice.XnSetupResponse; + + /* Global NG-RAN Node ID (M) */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_XnSetupResponse_IEs_t, ie1); + ie1->id = XNAP_ProtocolIE_ID_id_GlobalNG_RAN_node_ID; + ie1->criticality = XNAP_Criticality_reject; + ie1->value.present = XNAP_XnSetupResponse_IEs__value_PR_GlobalNG_RANNode_ID; + + XNAP_GlobalNG_RANNode_ID_t *global = &ie1->value.choice.GlobalNG_RANNode_ID; + global->present = XNAP_GlobalNG_RANNode_ID_PR_gNB; + asn1cCalloc(global->choice.gNB, gnb); + + MCC_MNC_TO_PLMNID(resp->plmn.mcc, resp->plmn.mnc, resp->plmn.mnc_digit_length, &gnb->plmn_id); + gnb->gnb_id.present = XNAP_GNB_ID_Choice_PR_gnb_ID; + MACRO_GNB_ID_TO_BIT_STRING(resp->gNB_id, &gnb->gnb_id.choice.gnb_ID); + + /* TAI Support List (M) */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_XnSetupResponse_IEs_t, ie2); + ie2->id = XNAP_ProtocolIE_ID_id_TAISupport_list; + ie2->criticality = XNAP_Criticality_reject; + ie2->value.present = XNAP_XnSetupResponse_IEs__value_PR_TAISupport_List; + + for (int i = 0; i < resp->num_tai; i++) { + asn1cSequenceAdd(ie2->value.choice.TAISupport_List.list, XNAP_TAISupport_Item_t, taiItem); + INT24_TO_OCTET_STRING(resp->tai_support[i].tac, &taiItem->tac); + + for (int j = 0; j < resp->tai_support[i].num_plmn; j++) { + const xnap_plmn_support_t *plmn = &resp->tai_support[i].plmn_support[j]; + asn1cSequenceAdd(taiItem->broadcastPLMNs.list, XNAP_BroadcastPLMNinTAISupport_Item_t, plmnItem); + MCC_MNC_TO_PLMNID(plmn->plmn.mcc, plmn->plmn.mnc, plmn->plmn.mnc_digit_length, &plmnItem->plmn_id); + + for (int k = 0; k < plmn->num_nssai; k++) { + asn1cSequenceAdd(plmnItem->tAISliceSupport_List.list, XNAP_S_NSSAI_t, nssai); + INT8_TO_OCTET_STRING(plmn->nssai[k].sst, &nssai->sst); + if (plmn->nssai[k].sd) { asn1cCalloc(nssai->sd, sd); INT24_TO_OCTET_STRING(plmn->nssai[k].sd, sd); } + } + } + } + + return pdu; +} + +/** + * @brief XnAP Setup Response decoding + */ +bool decode_xn_setup_response(xnap_setup_resp_t *out, const XNAP_XnAP_PDU_t *pdu) +{ + /* Check presence of message type */ + _EQ_CHECK_INT(pdu->present, XNAP_XnAP_PDU_PR_successfulOutcome); + AssertError(pdu->choice.successfulOutcome != NULL, return false, "successfulOutcome is NULL"); + _EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, XNAP_ProcedureCode_id_xnSetup); + _EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, XNAP_SuccessfulOutcome__value_PR_XnSetupResponse); + + /* XnSetupResponse container */ + XNAP_XnSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.XnSetupResponse; + XNAP_XnSetupResponse_IEs_t *ie; + + /* Check presence of mandatory IEs */ + XNAP_LIB_FIND_IE(XNAP_XnSetupResponse_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_GlobalNG_RAN_node_ID, true); + XNAP_LIB_FIND_IE(XNAP_XnSetupResponse_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_TAISupport_list, true); + + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + AssertError(in->protocolIEs.list.array[i] != NULL, return false, "protocolIEs.list.array[i] is NULL"); + ie = in->protocolIEs.list.array[i]; + + switch (ie->id) { + + case XNAP_ProtocolIE_ID_id_GlobalNG_RAN_node_ID: { + _EQ_CHECK_INT(ie->value.present, XNAP_XnSetupResponse_IEs__value_PR_GlobalNG_RANNode_ID); + XNAP_GlobalNG_RANNode_ID_t *global = &ie->value.choice.GlobalNG_RANNode_ID; + AssertError(global->present == XNAP_GlobalNG_RANNode_ID_PR_gNB, return false, "Only gNB supported"); + AssertError(global->choice.gNB != NULL, return false, "gNB is NULL"); + + PLMNID_TO_MCC_MNC(&global->choice.gNB->plmn_id, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length); + AssertError(global->choice.gNB->gnb_id.present == XNAP_GNB_ID_Choice_PR_gnb_ID, return false, "Unsupported gNB ID"); + MACRO_BIT_STRING_TO_GNB_ID(&global->choice.gNB->gnb_id.choice.gnb_ID, out->gNB_id); + } break; + + case XNAP_ProtocolIE_ID_id_TAISupport_list: { + _EQ_CHECK_INT(ie->value.present, XNAP_XnSetupResponse_IEs__value_PR_TAISupport_List); + out->num_tai = ie->value.choice.TAISupport_List.list.count; + out->tai_support = calloc_or_fail(out->num_tai, sizeof(*out->tai_support)); + + for (int m = 0; m < out->num_tai; m++) { + XNAP_TAISupport_Item_t *tai = ie->value.choice.TAISupport_List.list.array[m]; + OCTET_STRING_TO_INT24(&tai->tac, out->tai_support[m].tac); + + out->tai_support[m].num_plmn = tai->broadcastPLMNs.list.count; + out->tai_support[m].plmn_support = calloc_or_fail(out->tai_support[m].num_plmn, sizeof(*out->tai_support[m].plmn_support)); + + for (int j = 0; j < out->tai_support[m].num_plmn; j++) { + XNAP_BroadcastPLMNinTAISupport_Item_t *plmn_item = tai->broadcastPLMNs.list.array[j]; + xnap_plmn_support_t *plmn = &out->tai_support[m].plmn_support[j]; + + PLMNID_TO_MCC_MNC(&plmn_item->plmn_id, plmn->plmn.mcc, plmn->plmn.mnc, plmn->plmn.mnc_digit_length); + + plmn->num_nssai = plmn_item->tAISliceSupport_List.list.count; + plmn->nssai = calloc_or_fail(plmn->num_nssai, sizeof(*plmn->nssai)); + + for (int k = 0; k < plmn->num_nssai; k++) { + OCTET_STRING_TO_INT8(&plmn_item->tAISliceSupport_List.list.array[k]->sst, plmn->nssai[k].sst); + if (plmn_item->tAISliceSupport_List.list.array[k]->sd) { + OCTET_STRING_TO_INT24(plmn_item->tAISliceSupport_List.list.array[k]->sd, plmn->nssai[k].sd); + } + } + } + } + } break; + + default: + AssertError(0, return false, "Unknown XnAP IE id %ld\n", ie->id); + break; + } + } + return true; +} + +/** + * @brief XnAP Setup Response main equality check + */ +bool eq_xnap_setup_response(const xnap_setup_resp_t *a, const xnap_setup_resp_t *b) +{ + _EQ_CHECK_UINT32(a->gNB_id, b->gNB_id); + if (!eq_xnap_plmn(&a->plmn, &b->plmn)) return false; + + _EQ_CHECK_INT(a->num_tai, b->num_tai); + for (int i = 0; i < a->num_tai; i++) { + if (!eq_xnap_tai_support(&a->tai_support[i], &b->tai_support[i])) + return false; + } + + return true; +} + +/** + * @brief XnAP Setup Response memory management + */ +void free_xnap_setup_response(const xnap_setup_resp_t *msg) +{ + DevAssert(msg != NULL); + free_xnap_tai_support(msg->tai_support, msg->num_tai); +} + diff --git a/openair2/XNAP/lib/xnap_gNB_interface_management.h b/openair2/XNAP/lib/xnap_gNB_interface_management.h index a4e65d6e00..aab6f777e2 100644 --- a/openair2/XNAP/lib/xnap_gNB_interface_management.h +++ b/openair2/XNAP/lib/xnap_gNB_interface_management.h @@ -27,11 +27,15 @@ typedef struct XNAP_XnAP_PDU XNAP_XnAP_PDU_t; XNAP_XnAP_PDU_t *encode_xn_setup_request(const xnap_setup_req_t *req); +XNAP_XnAP_PDU_t *encode_xn_setup_response(const xnap_setup_resp_t *resp); bool decode_xn_setup_request(xnap_setup_req_t *req, const XNAP_XnAP_PDU_t *pdu); +bool decode_xn_setup_response(xnap_setup_resp_t *out, const XNAP_XnAP_PDU_t *pdu); bool eq_xnap_setup_request(const xnap_setup_req_t *a, const xnap_setup_req_t *b); +bool eq_xnap_setup_response(const xnap_setup_resp_t *a, const xnap_setup_resp_t *b); void free_xnap_setup_request(const xnap_setup_req_t *msg); +void free_xnap_setup_response(const xnap_setup_resp_t *msg); #endif /* XNAP_GNB_INTERFACE_MANAGEMENT_H_ */ diff --git a/openair2/XNAP/lib/xnap_lib_includes.h b/openair2/XNAP/lib/xnap_lib_includes.h index a67919413a..c45d9cf605 100644 --- a/openair2/XNAP/lib/xnap_lib_includes.h +++ b/openair2/XNAP/lib/xnap_lib_includes.h @@ -29,6 +29,7 @@ #include "XNAP_XnAP-PDU.h" #include "XNAP_ProtocolIE-Field.h" #include "XNAP_InitiatingMessage.h" +#include "XNAP_SuccessfulOutcome.h" #include "XNAP_GlobalgNB-ID.h" #include "XNAP_GlobalNG-RANNode-ID.h" @@ -37,6 +38,5 @@ #include "XNAP_S-NSSAI.h" #include "XNAP_BroadcastPLMNinTAISupport-Item.h" - #endif // XNAP_LIB_INCLUDES_H diff --git a/openair2/XNAP/tests/xnap_lib_test.c b/openair2/XNAP/tests/xnap_lib_test.c index c17f6b4967..610dc7d744 100644 --- a/openair2/XNAP/tests/xnap_lib_test.c +++ b/openair2/XNAP/tests/xnap_lib_test.c @@ -165,11 +165,96 @@ static void test_xn_setup_request(void) printf("%s() successful \n", __func__); } +/** + * 2. Xn Setup Response + */ +static void test_xn_setup_response(void) +{ + /* ---------- Common PLMNs ---------- */ + plmn_id_t plmn0 = { .mcc = 208, .mnc = 95, .mnc_digit_length = 2 }; + plmn_id_t plmn1 = { .mcc = 208, .mnc = 93, .mnc_digit_length = 2 }; + + /* ---------- TAI support (2) ---------- */ + xnap_tai_support_t *tai_support = calloc_or_fail(2, sizeof(*tai_support)); + + /* ================= TAI 0 ================= */ + tai_support[0].tac = 1; + tai_support[0].num_plmn = 2; + tai_support[0].plmn_support = calloc_or_fail(2, sizeof(*tai_support[0].plmn_support)); + + /* ---- TAI 0 / PLMN 0 ---- */ + tai_support[0].plmn_support[0].plmn = plmn0; + tai_support[0].plmn_support[0].num_nssai = 3; + tai_support[0].plmn_support[0].nssai = calloc_or_fail(3, sizeof(nssai_t)); + + tai_support[0].plmn_support[0].nssai[0] = (nssai_t){ .sst = 1, .sd = 0x010203 }; + tai_support[0].plmn_support[0].nssai[1] = (nssai_t){ .sst = 1, .sd = 0x010204 }; + tai_support[0].plmn_support[0].nssai[2] = (nssai_t){ .sst = 1, .sd = 0x010205 }; + + /* ---- TAI 0 / PLMN 1 ---- */ + tai_support[0].plmn_support[1].plmn = plmn1; + tai_support[0].plmn_support[1].num_nssai = 3; + tai_support[0].plmn_support[1].nssai = calloc_or_fail(3, sizeof(nssai_t)); + + tai_support[0].plmn_support[1].nssai[0] = (nssai_t){ .sst = 2, .sd = 0x020203 }; + tai_support[0].plmn_support[1].nssai[1] = (nssai_t){ .sst = 2, .sd = 0x020204 }; + tai_support[0].plmn_support[1].nssai[2] = (nssai_t){ .sst = 2, .sd = 0x020205 }; + + /* ================= TAI 1 ================= */ + tai_support[1].tac = 2; + tai_support[1].num_plmn = 2; + tai_support[1].plmn_support = calloc_or_fail(2, sizeof(*tai_support[1].plmn_support)); + + /* ---- TAI 1 / PLMN 0 ---- */ + tai_support[1].plmn_support[0].plmn = plmn0; + tai_support[1].plmn_support[0].num_nssai = 3; + tai_support[1].plmn_support[0].nssai = calloc_or_fail(3, sizeof(nssai_t)); + + tai_support[1].plmn_support[0].nssai[0] = (nssai_t){ .sst = 3, .sd = 0x030203 }; + tai_support[1].plmn_support[0].nssai[1] = (nssai_t){ .sst = 3, .sd = 0x030204 }; + tai_support[1].plmn_support[0].nssai[2] = (nssai_t){ .sst = 3, .sd = 0x030205 }; + + /* ---- TAI 1 / PLMN 1 ---- */ + tai_support[1].plmn_support[1].plmn = plmn1; + tai_support[1].plmn_support[1].num_nssai = 3; + tai_support[1].plmn_support[1].nssai = calloc_or_fail(3, sizeof(nssai_t)); + + tai_support[1].plmn_support[1].nssai[0] = (nssai_t){ .sst = 4, .sd = 0x040203 }; + tai_support[1].plmn_support[1].nssai[1] = (nssai_t){ .sst = 4, .sd = 0x040204 }; + tai_support[1].plmn_support[1].nssai[2] = (nssai_t){ .sst = 4, .sd = 0x040205 }; + + /* ---------- create message ---------- */ + xnap_setup_resp_t orig = { + .gNB_id = 0xABCDE, + .plmn = plmn0, + .num_tai = 2, + .tai_support = tai_support, + }; + /* ---------- encode ---------- */ + XNAP_XnAP_PDU_t *xnenc = encode_xn_setup_response(&orig); + XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc); + xnap_msg_free(xnenc); + + /* ---------- decode ---------- */ + xnap_setup_resp_t decoded = {0}; + bool ret = decode_xn_setup_response(&decoded, xndec); + AssertFatal(ret, "decode_xn_setup_response failed"); + xnap_msg_free(xndec); + + /* ---------- equality ---------- */ + ret = eq_xnap_setup_response(&orig, &decoded); + AssertFatal(ret, "Xn Setup Response mismatch\n"); + free_xnap_setup_response(&decoded); + free_xnap_setup_response(&orig); + printf("%s() successful \n", __func__); +} + int main() { printf("Starting XnAP Library Unit Tests...\n"); /* Xn Interface Testing */ test_xn_setup_request(); + test_xn_setup_response(); printf("All XnAP tests passed!\n"); return 0; From e34cb240736ed1aedc96e9498ac12d78cf25ad07 Mon Sep 17 00:00:00 2001 From: Rakesh BB Date: Thu, 5 Feb 2026 09:46:19 +0000 Subject: [PATCH 4/4] =?UTF-8?q?XNAP:=20add=20encode/decode=20and=20unit=20?= =?UTF-8?q?test=20for=20Xn=20Setup=20Failure=20=20=20-=20Add=20Xn=20Setup?= =?UTF-8?q?=20Failure=20message=20type=20definitions.=20=20=20-=20Implemen?= =?UTF-8?q?t=20encoder=20and=20decoder=20for=20Xn=20Setup=20Failure.=20=20?= =?UTF-8?q?=20=20=20=20=20Xn=20Setup=20Failure=20(3GPP=20TS=2038.423v16.2.?= =?UTF-8?q?0=20=C2=A79.1.3.3)=20=20=20=20=20=20=20-=20Cause=20(M)=20=20=20?= =?UTF-8?q?-=20Add=20equality=20check=20and=20memory=20management=20helper?= =?UTF-8?q?s.=20=20=20-=20Extend=20XNAP=20library=20unit=20tests=20to=20co?= =?UTF-8?q?ver=20Setup=20Failure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openair2/COMMON/xnap_messages_types.h | 105 ++++++++++++++++++ .../XNAP/lib/xnap_gNB_interface_management.c | 66 +++++++++++ .../XNAP/lib/xnap_gNB_interface_management.h | 4 + openair2/XNAP/lib/xnap_lib_common.c | 66 +++++++++++ openair2/XNAP/lib/xnap_lib_common.h | 4 + openair2/XNAP/lib/xnap_lib_includes.h | 2 + openair2/XNAP/tests/xnap_lib_test.c | 31 ++++++ 7 files changed, 278 insertions(+) diff --git a/openair2/COMMON/xnap_messages_types.h b/openair2/COMMON/xnap_messages_types.h index fc360d2558..bca8bc80f4 100644 --- a/openair2/COMMON/xnap_messages_types.h +++ b/openair2/COMMON/xnap_messages_types.h @@ -72,4 +72,109 @@ typedef struct { xnap_tai_support_t *tai_support; } xnap_setup_resp_t; +typedef enum xnap_cause_radio_network_e { + XNAP_CAUSE_RADIO_NETWORK_LAYER_CELL_NOT_AVAILABLE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_HANDOVER_DESIRABLE_FOR_RADIO_REASONS, + XNAP_CAUSE_RADIO_NETWORK_LAYER_HANDOVER_TARGET_NOT_ALLOWED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_INVALID_AMF_SET_ID, + XNAP_CAUSE_RADIO_NETWORK_LAYER_NO_RADIO_RESOURCES_AVAILABLE_IN_TARGET_CELL, + XNAP_CAUSE_RADIO_NETWORK_LAYER_PARTIAL_HANDOVER, + XNAP_CAUSE_RADIO_NETWORK_LAYER_REDUCE_LOAD_IN_SERVING_CELL, + XNAP_CAUSE_RADIO_NETWORK_LAYER_RESOURCE_OPTIMISATION_HANDOVER, + XNAP_CAUSE_RADIO_NETWORK_LAYER_TIME_CRITICAL_HANDOVER, + XNAP_CAUSE_RADIO_NETWORK_LAYER_TXN_RELOCOVERALL_EXPIRY, + XNAP_CAUSE_RADIO_NETWORK_LAYER_TXN_RELOCPREP_EXPIRY, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UNKNOWN_GUAMI_ID, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UNKNOWN_LOCAL_NG_RAN_NODE_UE_XNAP_ID, + XNAP_CAUSE_RADIO_NETWORK_LAYER_INCONSISTENT_REMOTE_NG_RAN_NODE_UE_XNAP_ID, + XNAP_CAUSE_RADIO_NETWORK_LAYER_ENCRYPTION_AND_OR_INTEGRITY_PROTECTION_ALGORITHMS_NOT_SUPPORTED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_PROTECTION_ALGORITHMS_NOT_SUPPORTED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_MULTIPLE_PDU_SESSION_ID_INSTANCES, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UNKNOWN_PDU_SESSION_ID, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UNKNOWN_QOS_FLOW_ID, + XNAP_CAUSE_RADIO_NETWORK_LAYER_MULTIPLE_QOS_FLOW_ID_INSTANCES, + XNAP_CAUSE_RADIO_NETWORK_LAYER_SWITCH_OFF_ONGOING, + XNAP_CAUSE_RADIO_NETWORK_LAYER_NOT_SUPPORTED_5QI_VALUE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_TXN_DCOVERALL_EXPIRY, + XNAP_CAUSE_RADIO_NETWORK_LAYER_TXN_DCPREP_EXPIRY, + XNAP_CAUSE_RADIO_NETWORK_LAYER_ACTION_DESIRABLE_FOR_RADIO_REASONS, + XNAP_CAUSE_RADIO_NETWORK_LAYER_REDUCE_LOAD, + XNAP_CAUSE_RADIO_NETWORK_LAYER_RESOURCE_OPTIMISATION, + XNAP_CAUSE_RADIO_NETWORK_LAYER_TIME_CRITICAL_ACTION, + XNAP_CAUSE_RADIO_NETWORK_LAYER_TARGET_NOT_ALLOWED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_NO_RADIO_RESOURCES_AVAILABLE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_INVALID_QOS_COMBINATION, + XNAP_CAUSE_RADIO_NETWORK_LAYER_ENCRYPTION_ALGORITHMS_NOT_SUPPORTED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_PROCEDURE_CANCELLED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_RRM_PURPOSE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_IMPROVE_USER_BIT_RATE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_USER_INACTIVITY, + XNAP_CAUSE_RADIO_NETWORK_LAYER_RADIO_CONNECTION_WITH_UE_LOST, + XNAP_CAUSE_RADIO_NETWORK_LAYER_FAILURE_IN_THE_RADIO_INTERFACE_PROCEDURE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_BEARER_OPTION_NOT_SUPPORTED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UP_INTEGRITY_PROTECTION_NOT_POSSIBLE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UP_CONFIDENTIALITY_PROTECTION_NOT_POSSIBLE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE_S, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UE_MAX_IP_DATA_RATE_REASON, + XNAP_CAUSE_RADIO_NETWORK_LAYER_CP_INTEGRITY_PROTECTION_FAILURE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UP_INTEGRITY_PROTECTION_FAILURE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_SLICE_NOT_SUPPORTED_BY_NG_RAN, + XNAP_CAUSE_RADIO_NETWORK_LAYER_MN_MOBILITY, + XNAP_CAUSE_RADIO_NETWORK_LAYER_SN_MOBILITY, + XNAP_CAUSE_RADIO_NETWORK_LAYER_COUNT_REACHES_MAX_VALUE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UNKNOWN_OLD_NG_RAN_NODE_UE_XNAP_ID, + XNAP_CAUSE_RADIO_NETWORK_LAYER_PDCP_OVERLOAD, + XNAP_CAUSE_RADIO_NETWORK_LAYER_DRB_ID_NOT_AVAILABLE, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UNSPECIFIED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_UE_CONTEXT_ID_NOT_KNOWN, + XNAP_CAUSE_RADIO_NETWORK_LAYER_NON_RELOCATION_OF_CONTEXT, + XNAP_CAUSE_RADIO_NETWORK_LAYER_CHO_CPC_RESOURCES_TOBECHANGED, + XNAP_CAUSE_RADIO_NETWORK_LAYER_RSN_NOT_AVAILABLE_FOR_THE_UP, + XNAP_CAUSE_RADIO_NETWORK_LAYER_NPN_ACCESS_DENIED +} xnap_cause_radio_network_t; + +typedef enum xnap_cause_transport_layer_e { + XNAP_CAUSE_TRANSPORT_LAYER_TRANSPORT_RESOURCE_UNAVAILABLE, + XNAP_CAUSE_TRANSPORT_LAYER_UNSPECIFIED +} xnap_cause_transport_layer_t; + +typedef enum xnap_cause_protocol_e { + XNAP_CAUSE_PROTOCOL_TRANSFER_SYNTAX_ERROR, + XNAP_CAUSE_PROTOCOL_ABSTRACT_SYNTAX_ERROR_REJECT, + XNAP_CAUSE_PROTOCOL_ABSTRACT_SYNTAX_ERROR_IGNORE_AND_NOTIFY, + XNAP_CAUSE_PROTOCOL_MESSAGE_NOT_COMPATIBLE_WITH_RECEIVER_STATE, + XNAP_CAUSE_PROTOCOL_SEMANTIC_ERROR, + XNAP_CAUSE_PROTOCOL_ABSTRACT_SYNTAX_ERROR_FALSELY_CONSTRUCTED, + XNAP_CAUSE_PROTOCOL_UNSPECIFIED +} xnap_cause_protocol_t; + +typedef enum xnap_cause_misc_e { + XNAP_CAUSE_MISC_CONTROL_PROCESSING_OVERLOAD, + XNAP_CAUSE_MISC_HARDWARE_FAILURE, + XNAP_CAUSE_MISC_O_AND_M_INTERVENTION, + XNAP_CAUSE_MISC_NOT_ENOUGH_USER_PLANE_PROCESSING_RESOURCES, + XNAP_CAUSE_MISC_UNSPECIFIED +} xnap_cause_misc_t; + +typedef enum xnap_cause_group_e { + XNAP_CAUSE_NOTHING, + XNAP_CAUSE_RADIO_NETWORK, + XNAP_CAUSE_TRANSPORT, + XNAP_CAUSE_PROTOCOL, + XNAP_CAUSE_MISC, +} xnap_cause_group_t; + +typedef struct xnap_cause_s { + /* Cause group (e.g. radioNetwork, transport, protocol, misc) */ + xnap_cause_group_t type; + /* Specific cause value within the selected cause group */ + uint8_t value; +} xnap_cause_t; + +/* 3GPP TS 38.423 9.1.3.3 – Xn Setup Failure */ +typedef struct { + // Cause (M) + xnap_cause_t cause; +} xnap_setup_failure_t; + #endif /* XNAP_MESSAGES_TYPES_H_ */ diff --git a/openair2/XNAP/lib/xnap_gNB_interface_management.c b/openair2/XNAP/lib/xnap_gNB_interface_management.c index 409ce7b967..f77543504d 100644 --- a/openair2/XNAP/lib/xnap_gNB_interface_management.c +++ b/openair2/XNAP/lib/xnap_gNB_interface_management.c @@ -403,3 +403,69 @@ void free_xnap_setup_response(const xnap_setup_resp_t *msg) free_xnap_tai_support(msg->tai_support, msg->num_tai); } +/** + * @brief XnAP Setup Failure encoding + */ +XNAP_XnAP_PDU_t *encode_xn_setup_failure(const xnap_setup_failure_t *fail) +{ + XNAP_XnAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Message type */ + pdu->present = XNAP_XnAP_PDU_PR_unsuccessfulOutcome; + asn1cCalloc(pdu->choice.unsuccessfulOutcome, failMsg); + failMsg->procedureCode = XNAP_ProcedureCode_id_xnSetup; + failMsg->criticality = XNAP_Criticality_reject; + failMsg->value.present = XNAP_UnsuccessfulOutcome__value_PR_XnSetupFailure; + + XNAP_XnSetupFailure_t *out = &failMsg->value.choice.XnSetupFailure; + + /* Cause (M) */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_XnSetupFailure_IEs_t, ie1); + ie1->id = XNAP_ProtocolIE_ID_id_Cause; + ie1->criticality = XNAP_Criticality_ignore; + ie1->value.present = XNAP_XnSetupFailure_IEs__value_PR_Cause; + xnap_gNB_set_cause(&ie1->value.choice.Cause, &fail->cause); + + return pdu; +} + +/** + * @brief XnAP Setup Failure decoding + */ +bool decode_xn_setup_failure(xnap_setup_failure_t *out, const XNAP_XnAP_PDU_t *pdu) +{ + /* Check message type */ + _EQ_CHECK_INT(pdu->present, XNAP_XnAP_PDU_PR_unsuccessfulOutcome); + AssertError(pdu->choice.unsuccessfulOutcome != NULL, return false, "unsuccessfulOutcome is NULL"); + _EQ_CHECK_LONG(pdu->choice.unsuccessfulOutcome->procedureCode, XNAP_ProcedureCode_id_xnSetup); + _EQ_CHECK_INT(pdu->choice.unsuccessfulOutcome->value.present, XNAP_UnsuccessfulOutcome__value_PR_XnSetupFailure); + + /* XnSetupFailure container */ + XNAP_XnSetupFailure_t *in = &pdu->choice.unsuccessfulOutcome->value.choice.XnSetupFailure; + XNAP_XnSetupFailure_IEs_t *ie; + + /* Check presence of mandatory IE */ + XNAP_LIB_FIND_IE(XNAP_XnSetupFailure_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_Cause, true); + + /* Decode Cause */ + _EQ_CHECK_INT(ie->value.present, XNAP_XnSetupFailure_IEs__value_PR_Cause); + out->cause = decode_xnap_cause(&ie->value.choice.Cause); + + return true; +} + +/** + * @brief XnAP Setup Failure equality check + */ +bool eq_xnap_setup_failure(const xnap_setup_failure_t *a, const xnap_setup_failure_t *b) +{ + return eq_xnap_cause(&a->cause, &b->cause); +} + +/** + * @brief XnAP Setup Failure memory management + */ +void free_xnap_setup_failure(xnap_setup_failure_t *msg) +{ + // nothing to free +} diff --git a/openair2/XNAP/lib/xnap_gNB_interface_management.h b/openair2/XNAP/lib/xnap_gNB_interface_management.h index aab6f777e2..f1ffb8811c 100644 --- a/openair2/XNAP/lib/xnap_gNB_interface_management.h +++ b/openair2/XNAP/lib/xnap_gNB_interface_management.h @@ -28,14 +28,18 @@ typedef struct XNAP_XnAP_PDU XNAP_XnAP_PDU_t; XNAP_XnAP_PDU_t *encode_xn_setup_request(const xnap_setup_req_t *req); XNAP_XnAP_PDU_t *encode_xn_setup_response(const xnap_setup_resp_t *resp); +XNAP_XnAP_PDU_t *encode_xn_setup_failure(const xnap_setup_failure_t *fail); bool decode_xn_setup_request(xnap_setup_req_t *req, const XNAP_XnAP_PDU_t *pdu); bool decode_xn_setup_response(xnap_setup_resp_t *out, const XNAP_XnAP_PDU_t *pdu); +bool decode_xn_setup_failure(xnap_setup_failure_t *out, const XNAP_XnAP_PDU_t *pdu); bool eq_xnap_setup_request(const xnap_setup_req_t *a, const xnap_setup_req_t *b); bool eq_xnap_setup_response(const xnap_setup_resp_t *a, const xnap_setup_resp_t *b); +bool eq_xnap_setup_failure(const xnap_setup_failure_t *a, const xnap_setup_failure_t *b); void free_xnap_setup_request(const xnap_setup_req_t *msg); void free_xnap_setup_response(const xnap_setup_resp_t *msg); +void free_xnap_setup_failure(xnap_setup_failure_t *msg); #endif /* XNAP_GNB_INTERFACE_MANAGEMENT_H_ */ diff --git a/openair2/XNAP/lib/xnap_lib_common.c b/openair2/XNAP/lib/xnap_lib_common.c index 9c6a09c80c..0d9b047ea9 100644 --- a/openair2/XNAP/lib/xnap_lib_common.c +++ b/openair2/XNAP/lib/xnap_lib_common.c @@ -23,6 +23,72 @@ #include "common/utils/assertions.h" #include "common/utils/utils.h" +int xnap_gNB_set_cause(XNAP_Cause_t *cause_p,const xnap_cause_t *in) +{ + DevAssert(cause_p != NULL); + switch (in->type) { + case XNAP_CAUSE_RADIO_NETWORK: + cause_p->present = XNAP_Cause_PR_radioNetwork; + cause_p->choice.radioNetwork = in->value; + break; + case XNAP_CAUSE_TRANSPORT: + cause_p->present = XNAP_Cause_PR_transport; + cause_p->choice.transport = in->value; + break; + case XNAP_CAUSE_PROTOCOL: + cause_p->present = XNAP_Cause_PR_protocol; + cause_p->choice.protocol = in->value; + break; + case XNAP_CAUSE_MISC: + cause_p->present = XNAP_Cause_PR_misc; + cause_p->choice.misc = in->value; + break; + case XNAP_CAUSE_NOTHING: + default: + AssertFatal(false, "unknown cause value %d\n", in->type); + break; + } + return 0; +} + +xnap_cause_t decode_xnap_cause(const XNAP_Cause_t *in) +{ + xnap_cause_t out = {0}; + switch (in->present) { + case XNAP_Cause_PR_radioNetwork: + out.type = XNAP_CAUSE_RADIO_NETWORK; + out.value = in->choice.radioNetwork; + break; + + case XNAP_Cause_PR_transport: + out.type = XNAP_CAUSE_TRANSPORT; + out.value = in->choice.transport; + break; + + case XNAP_Cause_PR_protocol: + out.type = XNAP_CAUSE_PROTOCOL; + out.value = in->choice.protocol; + break; + + case XNAP_Cause_PR_misc: + out.type = XNAP_CAUSE_MISC; + out.value = in->choice.misc; + break; + case XNAP_Cause_PR_NOTHING: + default: + PRINT_ERROR("received illegal XNAP cause %d\n", in->present); + break; + } + return out; +} + +bool eq_xnap_cause(const xnap_cause_t *a, const xnap_cause_t *b) +{ + _EQ_CHECK_INT(a->type, b->type); + _EQ_CHECK_INT(a->value, b->value); + return true; +} + bool eq_xnap_plmn(const plmn_id_t *a, const plmn_id_t *b) { _EQ_CHECK_INT(a->mcc, b->mcc); diff --git a/openair2/XNAP/lib/xnap_lib_common.h b/openair2/XNAP/lib/xnap_lib_common.h index cde0accd88..6186f55471 100644 --- a/openair2/XNAP/lib/xnap_lib_common.h +++ b/openair2/XNAP/lib/xnap_lib_common.h @@ -56,5 +56,9 @@ bool eq_xnap_plmn(const plmn_id_t *a, const plmn_id_t *b); bool eq_xnap_snssai(const nssai_t *a, const nssai_t *b); bool eq_xnap_tai_support(const xnap_tai_support_t *a, const xnap_tai_support_t *b); bool eq_xnap_plmn_support(const xnap_plmn_support_t *a, const xnap_plmn_support_t *b); +bool eq_xnap_cause(const xnap_cause_t *a, const xnap_cause_t *b); + +int xnap_gNB_set_cause(XNAP_Cause_t *cause_p,const xnap_cause_t *in); +xnap_cause_t decode_xnap_cause(const XNAP_Cause_t *in); #endif /* XNAP_LIB_COMMON_H_ */ diff --git a/openair2/XNAP/lib/xnap_lib_includes.h b/openair2/XNAP/lib/xnap_lib_includes.h index c45d9cf605..5e90adbea6 100644 --- a/openair2/XNAP/lib/xnap_lib_includes.h +++ b/openair2/XNAP/lib/xnap_lib_includes.h @@ -30,6 +30,7 @@ #include "XNAP_ProtocolIE-Field.h" #include "XNAP_InitiatingMessage.h" #include "XNAP_SuccessfulOutcome.h" +#include "XNAP_UnsuccessfulOutcome.h" #include "XNAP_GlobalgNB-ID.h" #include "XNAP_GlobalNG-RANNode-ID.h" @@ -37,6 +38,7 @@ #include "XNAP_TAISupport-Item.h" #include "XNAP_S-NSSAI.h" #include "XNAP_BroadcastPLMNinTAISupport-Item.h" +#include "XNAP_Cause.h" #endif // XNAP_LIB_INCLUDES_H diff --git a/openair2/XNAP/tests/xnap_lib_test.c b/openair2/XNAP/tests/xnap_lib_test.c index 610dc7d744..3c1ec3375a 100644 --- a/openair2/XNAP/tests/xnap_lib_test.c +++ b/openair2/XNAP/tests/xnap_lib_test.c @@ -249,12 +249,43 @@ static void test_xn_setup_response(void) printf("%s() successful \n", __func__); } +/** + * 3. Xn Setup Failure + */ +static void test_xn_setup_failure(void) +{ + /* ---------- create message ---------- */ + xnap_setup_failure_t orig = { + .cause.type = XNAP_CAUSE_TRANSPORT, + .cause.value = XNAP_CAUSE_TRANSPORT_LAYER_TRANSPORT_RESOURCE_UNAVAILABLE, + }; + + /* ---------- encode ---------- */ + XNAP_XnAP_PDU_t *xnenc = encode_xn_setup_failure(&orig); + XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc); + xnap_msg_free(xnenc); + + /* ---------- decode ---------- */ + xnap_setup_failure_t decoded = {0}; + bool ret = decode_xn_setup_failure(&decoded, xndec); + AssertFatal(ret, "decode_xn_setup_failure failed"); + xnap_msg_free(xndec); + + /* ---------- equality ---------- */ + ret = eq_xnap_setup_failure(&orig, &decoded); + AssertFatal(ret, "Xn Setup Failure mismatch\n"); + free_xnap_setup_failure(&decoded); + free_xnap_setup_failure(&orig); + printf("%s() successful \n", __func__); +} + int main() { printf("Starting XnAP Library Unit Tests...\n"); /* Xn Interface Testing */ test_xn_setup_request(); test_xn_setup_response(); + test_xn_setup_failure(); printf("All XnAP tests passed!\n"); return 0;