Files
openairinterface5g/openair2/XNAP/tests/xnap_lib_test.c
Mohammed Safwan b31846c62f XNAP: add encode/decode and unit test for Xn RAN Paging
- Add RAN Paging message type definitions, including paging DRX
  enumeration (§9.2.3.66) and RAN paging area cell-list
  structure (§9.2.3.38)
- Implement encoder and decoder for RAN Paging
    RAN Paging (3GPP TS 38.423v16.2.0 §9.1.1.7)
    - UE Identity Index Value (M)
    - UE RAN Paging Identity (M)
    - Paging DRX (M)
    - RAN Paging Area (M)
- Add equality check and memory management helpers
- Add required ASN.1 header includes for RAN Paging IEs
- Extend XNAP library unit tests to cover RAN Paging

Reviewed-by: Venkatareddy Akumalla <venkatareddy.akumalla@openairinterface.org>
Signed-off-by: Mohammed Safwan <mohammed.safwan@openairinterface.org>
2026-06-17 16:51:34 +05:30

809 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
/*
* \brief Test functions for XnAP encoding/decoding library
*/
#include <arpa/inet.h>
#include "common/utils/assertions.h"
#include "openair2/XNAP/lib/xnap_lib_common.h"
#include "openair2/XNAP/lib/xnap_gNB_interface_management.h"
#include "openair2/XNAP/lib/xnap_gNB_mobility_management.h"
#include "common/config/config_userapi.h"
configmodule_interface_t *uniqCfg = NULL;
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
UNUSED(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__);
}
/**
* 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__);
}
/**
* 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__);
}
/**
* 4. Xn Handover Request
*/
static void test_xn_handover_request(void)
{
/* ---------- Common identifiers ---------- */
plmn_id_t plmn0 = {.mcc = 208, .mnc = 95, .mnc_digit_length = 2};
/* ---------- Transport Layer Address (IPv4) ---------- */
transport_layer_addr_t tnl_addr_source = {.length = 4, .buffer = {192, 168, 1, 100}};
transport_layer_addr_t tnl_addr_n3 = {.length = 4, .buffer = {10, 0, 0, 1}};
/* ---------- S-NSSAI ---------- */
nssai_t nssai0 = {.sst = 1, .sd = 0x000001};
/* ---------- QoS Flow Level QoS Parameters ---------- */
xnap_qos_flow_param_t qos_params = {.qos_type = NON_DYNAMIC,
.nondyn = {.fiveQI = 9},
.arp = {.priority_level = 2,
.pre_emp_capability = PEC_SHALL_NOT_TRIGGER_PREEMPTION,
.pre_emp_vulnerability = PEV_NOT_PREEMPTABLE}};
/* ---------- QoS Flows To Be Setup List (Internet) ---------- */
xnap_qos_flow_tobe_setup_item_t *qos_list = calloc_or_fail(2, sizeof(*qos_list));
qos_list[0].qfi = 1;
qos_list[0].qos_params = qos_params;
qos_list[1].qfi = 2;
qos_list[1].qos_params = qos_params;
qos_list[1].qos_params.nondyn.fiveQI = 5;
/* ---------- QoS Flows (IMS) ---------- */
xnap_qos_flow_tobe_setup_item_t *qos_list_ims = calloc_or_fail(1, sizeof(*qos_list_ims));
qos_list_ims[0].qfi = 5;
qos_list_ims[0].qos_params = qos_params;
qos_list_ims[0].qos_params.nondyn.fiveQI = 2;
/* ---------- PDU Session Resources ---------- */
xnap_pdusession_resources_tobe_setup_item_t *pdusession_list = calloc_or_fail(2, sizeof(*pdusession_list));
/* ----- PDU Session 1 (Internet) ----- */
pdusession_list[0].pdusession_id = 1;
pdusession_list[0].nssai = calloc_or_fail(1, sizeof(nssai_t));
*pdusession_list[0].nssai = nssai0;
pdusession_list[0].n3_incoming = (gtpu_tunnel_t){.teid = 0x12345678, .addr = tnl_addr_n3};
pdusession_list[0].pdu_session_type = PDUSessionType_ipv4;
pdusession_list[0].num_qos = 2;
pdusession_list[0].qos_list = qos_list;
/* ----- PDU Session 2 (IMS) ----- */
nssai_t nssai_ims = {.sst = 1, .sd = 0x000002};
pdusession_list[1].pdusession_id = 2;
pdusession_list[1].nssai = calloc_or_fail(1, sizeof(nssai_t));
*pdusession_list[1].nssai = nssai_ims;
pdusession_list[1].n3_incoming = (gtpu_tunnel_t){.teid = 0x87654321, .addr = tnl_addr_n3};
pdusession_list[1].pdu_session_type = PDUSessionType_ipv4;
pdusession_list[1].num_qos = 1;
pdusession_list[1].qos_list = qos_list_ims;
/* ---------- UE Security Capabilities ---------- */
xnap_security_capabilities_t security_cap = {.nRencryption_algorithms = 0xC000,
.nRintegrity_algorithms = 0xC000,
.eUTRAencryption_algorithms = 0xC000,
.eUTRAintegrity_algorithms = 0xC000};
/* ---------- AS Security Key ---------- */
uint8_t as_key[32];
for (int i = 0; i < 32; i++)
as_key[i] = i;
/* ---------- RRC Context ---------- */
uint8_t rrc_data[] = {1, 2, 3, 4, 5};
byte_array_t rrc_context = {.buf = calloc_or_fail(5, sizeof(uint8_t)), .len = 5};
memcpy(rrc_context.buf, rrc_data, 5);
/* ---------- UE Context ---------- */
xnap_ue_context_info_t ue_context = {.ngc_ue_sig_ref = 0x123456789,
.cp_tnl_ip_source = tnl_addr_source,
.security_capabilities = security_cap,
.as_security_ncc = 1,
.ue_ambr = {.br_ul = 100000000, .br_dl = 200000000},
.rrc_context = rrc_context,
.num_pdu = 2,
.pdusession_resources_tobe_setup_list = pdusession_list};
memcpy(ue_context.as_security_key_ranstar, as_key, 32);
/* ---------- UE History Information ---------- */
ue_history_info_t *history_list = calloc_or_fail(1, sizeof(*history_list));
history_list[0].xnap_cell_type = XNAP_LastVisitedCell_Item_PR_nG_RAN_Cell;
uint8_t history_buf[] = {0x01, 0x02, 0x03, 0x04};
history_list[0].last_visited_cell_info.buf = calloc_or_fail(sizeof(history_buf), 1);
memcpy(history_list[0].last_visited_cell_info.buf, history_buf, sizeof(history_buf));
history_list[0].last_visited_cell_info.len = sizeof(history_buf);
/* ---------- GUAMI ---------- */
nr_guami_t guami = {.plmn = plmn0, .amf_region_id = 0x01, .amf_set_id = 0x0001, .amf_pointer = 0x01};
/* ---------- Target CGI ---------- */
xnap_ngran_cgi_t target_cgi = {.plmn_id = plmn0, .nrcell_id = 0x123456789};
/* ---------- Create message ---------- */
xnap_handover_req_t orig = {
.s_ng_node_ue_xnap_id = 0xABCD,
.cause = {.type = XNAP_CAUSE_RADIO_NETWORK, .value = XNAP_CAUSE_RADIO_NETWORK_LAYER_HANDOVER_DESIRABLE_FOR_RADIO_REASONS},
.target_cgi = target_cgi,
.guami = guami,
.ue_context = ue_context,
.num_last_visited_cells = 1,
.ue_history_info = history_list};
/* ---------- Encode ---------- */
XNAP_XnAP_PDU_t *xnenc = encode_xnap_handover_request(&orig);
XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc);
xnap_msg_free(xnenc);
/* ---------- Decode ---------- */
xnap_handover_req_t decoded = {0};
bool ret = decode_xnap_handover_request(&decoded, xndec);
AssertFatal(ret, "decode_xnap_handover_request failed");
xnap_msg_free(xndec);
/* ---------- Equality ---------- */
ret = eq_xnap_handover_request(&orig, &decoded);
AssertFatal(ret, "Xn Handover Request mismatch\n");
/* ---------- Cleanup ---------- */
free_xnap_handover_request(&decoded);
free_xnap_handover_request(&orig);
printf("%s() successful\n", __func__);
}
/**
* 5. Xn Handover Request Acknowledge
*/
static void test_xn_handover_request_acknowledge(void)
{
/* ---------- create message ---------- */
/* Create QoS Flows Admitted List for first PDU session */
xnap_qos_admitted_item_t *qos_list_1 = calloc_or_fail(2, sizeof(xnap_qos_admitted_item_t));
qos_list_1[0].qfi = 5;
qos_list_1[1].qfi = 9;
/* Create QoS Flows Admitted List for second PDU session */
xnap_qos_admitted_item_t *qos_list_2 = calloc_or_fail(1, sizeof(xnap_qos_admitted_item_t));
qos_list_2[0].qfi = 1;
/* Create PDU Session Resources Admitted List */
xnap_pdusession_admitted_item_t *pdu_list = calloc_or_fail(2, sizeof(xnap_pdusession_admitted_item_t));
pdu_list[0].pdusession_id = 10;
pdu_list[0].num_qos = 2;
pdu_list[0].qos_list = qos_list_1;
pdu_list[1].pdusession_id = 15;
pdu_list[1].num_qos = 1;
pdu_list[1].qos_list = qos_list_2;
/* Create transparent container ( Dummy data for RRC HandoverCommand) */
uint8_t container_data[] = {
0x00,
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x0b,
0x0c,
0x0d,
0x0e,
0x0f,
};
uint8_t *container_buf = malloc(sizeof(container_data));
memcpy(container_buf, container_data, sizeof(container_data));
xnap_handover_req_ack_t orig = {
.s_ng_node_ue_xnap_id = 123456,
.t_ng_node_ue_xnap_id = 789012,
.num_pdu_admitted = 2,
.pdusession_admitted_list = pdu_list,
.target2source =
{
.len = sizeof(container_data),
.buf = container_buf,
},
};
/* ---------- encode ---------- */
XNAP_XnAP_PDU_t *xnenc = encode_xnap_handover_request_acknowledge(&orig);
AssertFatal(xnenc != NULL, "encode_xnap_handover_request_acknowledge failed");
XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc);
xnap_msg_free(xnenc);
/* ---------- decode ---------- */
xnap_handover_req_ack_t decoded = {0};
bool ret = decode_xnap_handover_request_acknowledge(&decoded, xndec);
AssertFatal(ret, "decode_xnap_handover_request_acknowledge failed");
xnap_msg_free(xndec);
/* ---------- equality ---------- */
ret = eq_xnap_handover_request_acknowledge(&orig, &decoded);
AssertFatal(ret, "XnAP Handover Request Acknowledge mismatch\n");
/* ---------- cleanup ---------- */
free_xnap_handover_request_acknowledge(&decoded);
free_xnap_handover_request_acknowledge(&orig);
printf("%s() successful \n", __func__);
}
/**
* 6. Xn Handover Preparation Failure
*/
static void test_xn_handover_preparation_failure(void)
{
/* ---------- create message ---------- */
xnap_handover_preparation_failure_t orig = {
.s_ng_node_ue_xnap_id = 123456,
.cause =
{
.type = XNAP_CAUSE_RADIO_NETWORK,
.value = XNAP_CAUSE_RADIO_NETWORK_LAYER_NO_RADIO_RESOURCES_AVAILABLE_IN_TARGET_CELL,
},
};
/* ---------- encode ---------- */
XNAP_XnAP_PDU_t *xnenc = encode_xnap_handover_preparation_failure(&orig);
AssertFatal(xnenc != NULL, "encode_xnap_handover_preparation_failure failed");
XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc);
xnap_msg_free(xnenc);
/* ---------- decode ---------- */
xnap_handover_preparation_failure_t decoded = {0};
bool ret = decode_xnap_handover_preparation_failure(&decoded, xndec);
AssertFatal(ret, "decode_xnap_handover_preparation_failure failed");
xnap_msg_free(xndec);
/* ---------- equality ---------- */
ret = eq_xnap_handover_preparation_failure(&orig, &decoded);
AssertFatal(ret, "XnAP Handover Preparation Failure mismatch\n");
/* ---------- cleanup ---------- */
free_xnap_handover_preparation_failure(&decoded);
free_xnap_handover_preparation_failure(&orig);
printf("%s() successful \n", __func__);
}
/**
* 7. XnAP SN Status Transfer Testing
*/
static void test_xn_sn_status_transfer(void)
{
/* ---------- create message ---------- */
xnap_sn_status_transfer_t orig = {
.s_ng_node_ue_xnap_id = 123456,
.t_ng_node_ue_xnap_id = 789012,
.ran_status = {
.nb_drb = 3,
.drb_status_list = {
/* DRB 1 - 12-bit PDCP SN */
{
.drb_id = 1,
.ul_count = {
.pdcp_sn = 2048,
.hfn = 15,
.sn_len = XNAP_SN_LENGTH_12,
},
.dl_count = {
.pdcp_sn = 3072,
.hfn = 20,
.sn_len = XNAP_SN_LENGTH_12,
},
},
/* DRB 2 - 18-bit PDCP SN */
{
.drb_id = 5,
.ul_count = {
.pdcp_sn = 131072,
.hfn = 100,
.sn_len = XNAP_SN_LENGTH_18,
},
.dl_count = {
.pdcp_sn = 200000,
.hfn = 150,
.sn_len = XNAP_SN_LENGTH_18,
},
},
/* DRB 3 - Mixed: 12-bit UL, 18-bit DL */
{
.drb_id = 9,
.ul_count = {
.pdcp_sn = 1024,
.hfn = 5,
.sn_len = XNAP_SN_LENGTH_12,
},
.dl_count = {
.pdcp_sn = 100000,
.hfn = 75,
.sn_len = XNAP_SN_LENGTH_18,
},
},
},
},
};
/* ---------- encode ---------- */
XNAP_XnAP_PDU_t *xnenc = encode_xnap_sn_status_transfer(&orig);
AssertFatal(xnenc != NULL, "encode_xnap_sn_status_transfer failed");
XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc);
xnap_msg_free(xnenc);
/* ---------- decode ---------- */
xnap_sn_status_transfer_t decoded = {0};
bool ret = decode_xnap_sn_status_transfer(&decoded, xndec);
AssertFatal(ret, "decode_xnap_sn_status_transfer failed");
xnap_msg_free(xndec);
/* ---------- equality ---------- */
ret = eq_xnap_sn_status_transfer(&orig, &decoded);
AssertFatal(ret, "XnAP SN Status Transfer mismatch\n");
/* ---------- cleanup ---------- */
free_xnap_sn_status_transfer(&decoded);
free_xnap_sn_status_transfer(&orig);
printf("%s() successful \n", __func__);
}
/**
* 8. XnAP UE Context Release Testing
*/
static void test_xn_ue_context_release(void)
{
/* ---------- create message ---------- */
xnap_ue_context_release_t orig = {
.s_ng_node_ue_xnap_id = 123456,
.t_ng_node_ue_xnap_id = 789012,
};
/* ---------- encode ---------- */
XNAP_XnAP_PDU_t *xnenc = encode_xnap_ue_context_release(&orig);
AssertFatal(xnenc != NULL, "encode_xnap_ue_context_release failed");
XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc);
xnap_msg_free(xnenc);
/* ---------- decode ---------- */
xnap_ue_context_release_t decoded = {0};
bool ret = decode_xnap_ue_context_release(&decoded, xndec);
AssertFatal(ret, "decode_xnap_ue_context_release failed");
xnap_msg_free(xndec);
/* ---------- equality ---------- */
ret = eq_xnap_ue_context_release(&orig, &decoded);
AssertFatal(ret, "XnAP UE Context Release mismatch\n");
/* ---------- cleanup ---------- */
free_xnap_ue_context_release(&decoded);
free_xnap_ue_context_release(&orig);
printf("%s() successful \n", __func__);
}
/**
* 9. XnAP Handover Cancel Testing
*/
static void test_xn_handover_cancel(void)
{
/* ---------- create message ---------- */
xnap_handover_cancel_t orig = {
.s_ng_node_ue_xnap_id = 111111,
.cause = {
.type = XNAP_CAUSE_RADIO_NETWORK,
.value = XNAP_CAUSE_RADIO_NETWORK_LAYER_PROCEDURE_CANCELLED,
},
};
/* ---------- encode ---------- */
XNAP_XnAP_PDU_t *xnenc = encode_xnap_handover_cancel(&orig);
AssertFatal(xnenc != NULL, "encode_xnap_handover_cancel failed");
XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc);
xnap_msg_free(xnenc);
/* ---------- decode ---------- */
xnap_handover_cancel_t decoded = {0};
bool ret = decode_xnap_handover_cancel(&decoded, xndec);
AssertFatal(ret, "decode_xnap_handover_cancel failed");
xnap_msg_free(xndec);
/* ---------- equality ---------- */
ret = eq_xnap_handover_cancel(&orig, &decoded);
AssertFatal(ret, "XnAP Handover Cancel mismatch\n");
/* ---------- cleanup ---------- */
free_xnap_handover_cancel(&decoded);
free_xnap_handover_cancel(&orig);
printf("%s() successful\n", __func__);
}
/**
* 10. XnAP Handover Success Testing
*/
static void test_xn_handover_success(void)
{
/* ---------- create message ---------- */
plmn_id_t plmn0 = {.mcc = 208, .mnc = 95, .mnc_digit_length = 2};
xnap_handover_success_t orig = {
.s_ng_node_ue_xnap_id = 333333,
.t_ng_node_ue_xnap_id = 444444,
.target_cgi = {.plmn_id = plmn0, .nrcell_id = 0xABCDEF012ULL},
};
/* ---------- encode ---------- */
XNAP_XnAP_PDU_t *xnenc = encode_xnap_handover_success(&orig);
AssertFatal(xnenc != NULL, "encode_xnap_handover_success failed");
XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc);
xnap_msg_free(xnenc);
/* ---------- decode ---------- */
xnap_handover_success_t decoded = {0};
bool ret = decode_xnap_handover_success(&decoded, xndec);
AssertFatal(ret, "decode_xnap_handover_success failed");
xnap_msg_free(xndec);
/* ---------- equality ---------- */
ret = eq_xnap_handover_success(&orig, &decoded);
AssertFatal(ret, "XnAP Handover Success mismatch\n");
/* ---------- cleanup ---------- */
free_xnap_handover_success(&decoded);
free_xnap_handover_success(&orig);
printf("%s() successful\n", __func__);
}
/**
* 11. XnAP RAN Paging Testing cell_List and rANAreaID_List variants
*/
static void test_xn_ran_paging(void)
{
/* ---------- create message ---------- */
plmn_id_t plmn0 = {.mcc = 208, .mnc = 95, .mnc_digit_length = 2};
uint64_t *cell_ids = calloc_or_fail(3, sizeof(uint64_t));
cell_ids[0] = 0x123456789ULL & 0xFFFFFFFFFULL;
cell_ids[1] = 0xABCDEF012ULL & 0xFFFFFFFFFULL;
cell_ids[2] = 0x100200300ULL & 0xFFFFFFFFFULL;
xnap_ran_area_id_t *ran_area_ids = calloc_or_fail(2, sizeof(xnap_ran_area_id_t));
ran_area_ids[0] = (xnap_ran_area_id_t){.tac = 0x001234, .ranac_present = true, .ranac = 7};
ran_area_ids[1] = (xnap_ran_area_id_t){.tac = 0x005678, .ranac_present = false};
xnap_ran_paging_t cases[] = {
{.ue_identity_index_value = 0x2A5,
.ue_ran_paging_identity = 0xABCDE01234ULL,
.paging_drx = XNAP_PAGING_DRX_128,
.ran_paging_area = {.plmn = plmn0,
.choice = XNAP_RAN_PAGING_AREA_CELL_LIST,
.num_cells = 3,
.cell_ids = cell_ids}},
{.ue_identity_index_value = 0x155,
.ue_ran_paging_identity = 0x1234567890ULL,
.paging_drx = XNAP_PAGING_DRX_64,
.ran_paging_area = {.plmn = plmn0,
.choice = XNAP_RAN_PAGING_AREA_RAN_AREA_ID,
.num_ran_area_ids = 2,
.ran_area_ids = ran_area_ids}},
};
for (size_t i = 0; i < sizeof(cases) / sizeof(*cases); i++) {
/* ---------- encode ---------- */
XNAP_XnAP_PDU_t *xnenc = encode_xnap_ran_paging(&cases[i]);
AssertFatal(xnenc != NULL, "encode_xnap_ran_paging failed");
XNAP_XnAP_PDU_t *xndec = xnap_encode_decode(xnenc);
xnap_msg_free(xnenc);
/* ---------- decode ---------- */
xnap_ran_paging_t decoded = {0};
bool ret = decode_xnap_ran_paging(&decoded, xndec);
AssertFatal(ret, "decode_xnap_ran_paging failed");
xnap_msg_free(xndec);
/* ---------- equality ---------- */
ret = eq_xnap_ran_paging(&cases[i], &decoded);
AssertFatal(ret, "XnAP RAN Paging mismatch (case %zu)\n", i);
/* ---------- cleanup ---------- */
free_xnap_ran_paging(&decoded);
free_xnap_ran_paging(&cases[i]);
}
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();
/* Xn Handover Testing*/
test_xn_handover_request();
test_xn_handover_request_acknowledge();
test_xn_handover_preparation_failure();
test_xn_sn_status_transfer();
test_xn_ue_context_release();
test_xn_handover_cancel();
test_xn_handover_success();
test_xn_ran_paging();
printf("All XnAP tests passed!\n");
return 0;
}