mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
- 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>
809 lines
28 KiB
C
809 lines
28 KiB
C
/*
|
||
* 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;
|
||
}
|