XNAP: Introduce XnAP library framework and add encode/decode, unit test for Xn Setup Request

- 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 <sreeshmau@iisc.ac.in>
This commit is contained in:
Rakesh BB
2026-03-04 07:04:32 +00:00
parent 5d9f7b41c1
commit 08b454bd15
12 changed files with 734 additions and 5 deletions

View File

@@ -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)

View File

@@ -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_ */

View File

@@ -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()

View File

@@ -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()

View File

@@ -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);
}

View File

@@ -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 <stdbool.h>
#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_ */

View File

@@ -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;
}

View File

@@ -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 <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#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_ */

View File

@@ -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

View File

@@ -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}
)

View File

@@ -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 <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <arpa/inet.h>
#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;
}

View File

@@ -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