From b31846c62f98052963d1079bd05c75758ebdce00 Mon Sep 17 00:00:00 2001 From: Mohammed Safwan Date: Fri, 12 Jun 2026 17:47:43 +0530 Subject: [PATCH] XNAP: add encode/decode and unit test for Xn RAN Paging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 Signed-off-by: Mohammed Safwan --- openair2/COMMON/xnap_messages_types.h | 50 ++++ .../XNAP/lib/xnap_gNB_mobility_management.c | 222 ++++++++++++++++++ .../XNAP/lib/xnap_gNB_mobility_management.h | 4 + openair2/XNAP/lib/xnap_lib_includes.h | 10 + openair2/XNAP/tests/xnap_lib_test.c | 60 +++++ 5 files changed, 346 insertions(+) diff --git a/openair2/COMMON/xnap_messages_types.h b/openair2/COMMON/xnap_messages_types.h index 28be46b727..c4d3217ba3 100644 --- a/openair2/COMMON/xnap_messages_types.h +++ b/openair2/COMMON/xnap_messages_types.h @@ -400,4 +400,54 @@ typedef struct { xnap_ngran_cgi_t target_cgi; } xnap_handover_success_t; +/* 3GPP TS 38.423 9.2.3.66 – Paging DRX */ +typedef enum { + XNAP_PAGING_DRX_32 = 0, + XNAP_PAGING_DRX_64, + XNAP_PAGING_DRX_128, + XNAP_PAGING_DRX_256, + XNAP_PAGING_DRX_512, + XNAP_PAGING_DRX_1024, +} xnap_paging_drx_t; + +typedef enum { + XNAP_RAN_PAGING_AREA_CELL_LIST = 0, + XNAP_RAN_PAGING_AREA_RAN_AREA_ID, +} xnap_ran_paging_area_choice_t; + +/* RAN Area ID entry: TAC (M) + optional RANAC */ +typedef struct { + uint32_t tac; /* 24-bit Tracking Area Code (M) */ + bool ranac_present; + uint8_t ranac; /* RAN Area Code 0..255 (O) */ +} xnap_ran_area_id_t; + +/* 3GPP TS 38.423 9.2.3.38 – RAN Paging Area */ +typedef struct { + plmn_id_t plmn; + xnap_ran_paging_area_choice_t choice; + union { + struct { + uint8_t num_cells; + uint64_t *cell_ids; /* NR-Cell-Identity, 36-bit values */ + }; + struct { + uint8_t num_ran_area_ids; + xnap_ran_area_id_t *ran_area_ids; + }; + }; +} xnap_ran_paging_area_t; + +/* 3GPP TS 38.423 9.1.1.7 – RAN Paging */ +typedef struct { + /* UE Identity Index Value – 10-bit index (M) */ + uint16_t ue_identity_index_value; + /* UE RAN Paging Identity – I-RNTI, 40-bit (M) */ + uint64_t ue_ran_paging_identity; + /* Paging DRX (M) */ + xnap_paging_drx_t paging_drx; + /* RAN Paging Area (M) */ + xnap_ran_paging_area_t ran_paging_area; +} xnap_ran_paging_t; + #endif /* XNAP_MESSAGES_TYPES_H_ */ diff --git a/openair2/XNAP/lib/xnap_gNB_mobility_management.c b/openair2/XNAP/lib/xnap_gNB_mobility_management.c index 7cfbda1db6..d32e3eadcc 100644 --- a/openair2/XNAP/lib/xnap_gNB_mobility_management.c +++ b/openair2/XNAP/lib/xnap_gNB_mobility_management.c @@ -1488,3 +1488,225 @@ void free_xnap_handover_success(xnap_handover_success_t *msg) // Nothing to free UNUSED(msg); } + +/** + * @brief XnAP RAN Paging encoding + */ +XNAP_XnAP_PDU_t *encode_xnap_ran_paging(const xnap_ran_paging_t *msg) +{ + XNAP_XnAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + pdu->present = XNAP_XnAP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, initMsg); + initMsg->procedureCode = XNAP_ProcedureCode_id_rANPaging; + initMsg->criticality = XNAP_Criticality_reject; + initMsg->value.present = XNAP_InitiatingMessage__value_PR_RANPaging; + + XNAP_RANPaging_t *out = &initMsg->value.choice.RANPaging; + + /* UE Identity Index Value (M) – 10-bit BIT STRING */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_RANPaging_IEs_t, ie1); + ie1->id = XNAP_ProtocolIE_ID_id_UEIdentityIndexValue; + ie1->criticality = XNAP_Criticality_reject; + ie1->value.present = XNAP_RANPaging_IEs__value_PR_UEIdentityIndexValue; + XNAP_UEIdentityIndexValue_t *ue_idx = &ie1->value.choice.UEIdentityIndexValue; + ue_idx->present = XNAP_UEIdentityIndexValue_PR_indexLength10; + BIT_STRING_t *idx_bs = &ue_idx->choice.indexLength10; + UEIDENTITYINDEX_TO_BIT_STRING(msg->ue_identity_index_value, idx_bs); + + /* UE RAN Paging Identity (M) – I-RNTI, 40-bit BIT STRING */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_RANPaging_IEs_t, ie2); + ie2->id = XNAP_ProtocolIE_ID_id_UERANPagingIdentity; + ie2->criticality = XNAP_Criticality_ignore; + ie2->value.present = XNAP_RANPaging_IEs__value_PR_UERANPagingIdentity; + XNAP_UERANPagingIdentity_t *ue_paging_id = &ie2->value.choice.UERANPagingIdentity; + ue_paging_id->present = XNAP_UERANPagingIdentity_PR_i_RNTI_full; + BIT_STRING_t *rnti_bs = &ue_paging_id->choice.i_RNTI_full; + IRNTI_TO_BIT_STRING(msg->ue_ran_paging_identity, rnti_bs); + + /* Paging DRX (M) */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_RANPaging_IEs_t, ie3); + ie3->id = XNAP_ProtocolIE_ID_id_PagingDRX; + ie3->criticality = XNAP_Criticality_ignore; + ie3->value.present = XNAP_RANPaging_IEs__value_PR_PagingDRX; + ie3->value.choice.PagingDRX = msg->paging_drx; + + /* RAN Paging Area (M) */ + asn1cSequenceAdd(out->protocolIEs.list, XNAP_RANPaging_IEs_t, ie4); + ie4->id = XNAP_ProtocolIE_ID_id_RANPagingArea; + ie4->criticality = XNAP_Criticality_reject; + ie4->value.present = XNAP_RANPaging_IEs__value_PR_RANPagingArea; + XNAP_RANPagingArea_t *paging_area = &ie4->value.choice.RANPagingArea; + MCC_MNC_TO_PLMNID(msg->ran_paging_area.plmn.mcc, + msg->ran_paging_area.plmn.mnc, + msg->ran_paging_area.plmn.mnc_digit_length, + &paging_area->pLMN_Identity); + if (msg->ran_paging_area.choice == XNAP_RAN_PAGING_AREA_CELL_LIST) { + paging_area->rANPagingAreaChoice.present = XNAP_RANPagingAreaChoice_PR_cell_List; + asn1cCalloc(paging_area->rANPagingAreaChoice.choice.cell_List, cell_list); + for (int i = 0; i < msg->ran_paging_area.num_cells; i++) { + asn1cSequenceAdd(cell_list->list, XNAP_NG_RAN_Cell_Identity_t, cell_item); + cell_item->present = XNAP_NG_RAN_Cell_Identity_PR_nr; + NR_CELL_ID_TO_BIT_STRING(msg->ran_paging_area.cell_ids[i], &cell_item->choice.nr); + } + } else { + paging_area->rANPagingAreaChoice.present = XNAP_RANPagingAreaChoice_PR_rANAreaID_List; + asn1cCalloc(paging_area->rANPagingAreaChoice.choice.rANAreaID_List, ran_area_list); + for (int i = 0; i < msg->ran_paging_area.num_ran_area_ids; i++) { + const xnap_ran_area_id_t *src = &msg->ran_paging_area.ran_area_ids[i]; + asn1cSequenceAdd(ran_area_list->list, XNAP_RANAreaID_t, ran_area_item); + INT24_TO_OCTET_STRING(src->tac, &ran_area_item->tAC); + if (src->ranac_present) { + ran_area_item->rANAC = calloc_or_fail(1, sizeof(*ran_area_item->rANAC)); + *ran_area_item->rANAC = src->ranac; + } + } + } + + return pdu; +} + +/** + * @brief XnAP RAN Paging decoding + */ +bool decode_xnap_ran_paging(xnap_ran_paging_t *out, const XNAP_XnAP_PDU_t *pdu) +{ + _EQ_CHECK_INT(pdu->present, XNAP_XnAP_PDU_PR_initiatingMessage); + AssertError(pdu->choice.initiatingMessage != NULL, return false, "initiatingMessage is NULL"); + _EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, XNAP_ProcedureCode_id_rANPaging); + _EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, XNAP_InitiatingMessage__value_PR_RANPaging); + + XNAP_RANPaging_t *in = &pdu->choice.initiatingMessage->value.choice.RANPaging; + XNAP_RANPaging_IEs_t *ie; + + XNAP_LIB_FIND_IE(XNAP_RANPaging_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_UEIdentityIndexValue, true); + XNAP_LIB_FIND_IE(XNAP_RANPaging_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_UERANPagingIdentity, true); + XNAP_LIB_FIND_IE(XNAP_RANPaging_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_PagingDRX, true); + XNAP_LIB_FIND_IE(XNAP_RANPaging_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_RANPagingArea, true); + + for (int i = 0; i < in->protocolIEs.list.count; i++) { + DevAssert(in->protocolIEs.list.array[i]); + ie = in->protocolIEs.list.array[i]; + + switch (ie->id) { + case XNAP_ProtocolIE_ID_id_UEIdentityIndexValue: { + _EQ_CHECK_INT(ie->value.present, XNAP_RANPaging_IEs__value_PR_UEIdentityIndexValue); + const XNAP_UEIdentityIndexValue_t *ue_idx = &ie->value.choice.UEIdentityIndexValue; + if (ue_idx->present != XNAP_UEIdentityIndexValue_PR_indexLength10) + return false; + out->ue_identity_index_value = BIT_STRING_to_uint16(&ue_idx->choice.indexLength10); + } break; + + case XNAP_ProtocolIE_ID_id_UERANPagingIdentity: { + _EQ_CHECK_INT(ie->value.present, XNAP_RANPaging_IEs__value_PR_UERANPagingIdentity); + const XNAP_UERANPagingIdentity_t *ue_paging_id = &ie->value.choice.UERANPagingIdentity; + if (ue_paging_id->present != XNAP_UERANPagingIdentity_PR_i_RNTI_full) + return false; + out->ue_ran_paging_identity = BIT_STRING_to_uint64(&ue_paging_id->choice.i_RNTI_full); + } break; + + case XNAP_ProtocolIE_ID_id_PagingDRX: { + _EQ_CHECK_INT(ie->value.present, XNAP_RANPaging_IEs__value_PR_PagingDRX); + out->paging_drx = ie->value.choice.PagingDRX; + } break; + + case XNAP_ProtocolIE_ID_id_RANPagingArea: { + _EQ_CHECK_INT(ie->value.present, XNAP_RANPaging_IEs__value_PR_RANPagingArea); + const XNAP_RANPagingArea_t *paging_area = &ie->value.choice.RANPagingArea; + PLMNID_TO_MCC_MNC(&paging_area->pLMN_Identity, + out->ran_paging_area.plmn.mcc, + out->ran_paging_area.plmn.mnc, + out->ran_paging_area.plmn.mnc_digit_length); + switch (paging_area->rANPagingAreaChoice.present) { + case XNAP_RANPagingAreaChoice_PR_cell_List: { + out->ran_paging_area.choice = XNAP_RAN_PAGING_AREA_CELL_LIST; + const XNAP_NG_RAN_Cell_Identity_ListinRANPagingArea_t *cell_list = paging_area->rANPagingAreaChoice.choice.cell_List; + out->ran_paging_area.num_cells = cell_list->list.count; + out->ran_paging_area.cell_ids = calloc_or_fail(out->ran_paging_area.num_cells, sizeof(uint64_t)); + for (int j = 0; j < cell_list->list.count; j++) { + const XNAP_NG_RAN_Cell_Identity_t *cell = cell_list->list.array[j]; + if (cell->present != XNAP_NG_RAN_Cell_Identity_PR_nr) + return false; + BIT_STRING_TO_NR_CELL_IDENTITY(&cell->choice.nr, out->ran_paging_area.cell_ids[j]); + } + } break; + case XNAP_RANPagingAreaChoice_PR_rANAreaID_List: { + out->ran_paging_area.choice = XNAP_RAN_PAGING_AREA_RAN_AREA_ID; + const XNAP_RANAreaID_List_t *ran_area_list = paging_area->rANPagingAreaChoice.choice.rANAreaID_List; + out->ran_paging_area.num_ran_area_ids = ran_area_list->list.count; + out->ran_paging_area.ran_area_ids = calloc_or_fail(out->ran_paging_area.num_ran_area_ids, sizeof(xnap_ran_area_id_t)); + for (int j = 0; j < ran_area_list->list.count; j++) { + const XNAP_RANAreaID_t *ran_area = ran_area_list->list.array[j]; + xnap_ran_area_id_t *dst = &out->ran_paging_area.ran_area_ids[j]; + OCTET_STRING_TO_INT24(&ran_area->tAC, dst->tac); + if (ran_area->rANAC) { + dst->ranac_present = true; + dst->ranac = *ran_area->rANAC; + } + } + } break; + default: + AssertError(0, return false, "Unknown RANPagingAreaChoice.present=%d\n", paging_area->rANPagingAreaChoice.present); + } + } break; + + case XNAP_ProtocolIE_ID_id_PagingPriority: + PRINT_ERROR("XNAP_ProtocolIE_ID_id %ld not handled, skipping\n", ie->id); + break; + + case XNAP_ProtocolIE_ID_id_AssistanceDataForRANPaging: + PRINT_ERROR("XNAP_ProtocolIE_ID_id %ld not handled, skipping\n", ie->id); + break; + + case XNAP_ProtocolIE_ID_id_UERadioCapabilityForPaging: + PRINT_ERROR("XNAP_ProtocolIE_ID_id %ld not handled, skipping\n", ie->id); + break; + + default: + PRINT_ERROR("XNAP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief XnAP RAN Paging equality function + */ +bool eq_xnap_ran_paging(const xnap_ran_paging_t *a, const xnap_ran_paging_t *b) +{ + _EQ_CHECK_INT(a->ue_identity_index_value, b->ue_identity_index_value); + _EQ_CHECK_UINT64(a->ue_ran_paging_identity, b->ue_ran_paging_identity); + _EQ_CHECK_INT(a->paging_drx, b->paging_drx); + + if (!eq_xnap_plmn(&a->ran_paging_area.plmn, &b->ran_paging_area.plmn)) + return false; + _EQ_CHECK_INT(a->ran_paging_area.choice, b->ran_paging_area.choice); + if (a->ran_paging_area.choice == XNAP_RAN_PAGING_AREA_CELL_LIST) { + _EQ_CHECK_INT(a->ran_paging_area.num_cells, b->ran_paging_area.num_cells); + for (int i = 0; i < a->ran_paging_area.num_cells; i++) + _EQ_CHECK_UINT64(a->ran_paging_area.cell_ids[i], b->ran_paging_area.cell_ids[i]); + } else { + _EQ_CHECK_INT(a->ran_paging_area.num_ran_area_ids, b->ran_paging_area.num_ran_area_ids); + for (int i = 0; i < a->ran_paging_area.num_ran_area_ids; i++) { + _EQ_CHECK_UINT32(a->ran_paging_area.ran_area_ids[i].tac, b->ran_paging_area.ran_area_ids[i].tac); + _EQ_CHECK_INT(a->ran_paging_area.ran_area_ids[i].ranac_present, b->ran_paging_area.ran_area_ids[i].ranac_present); + if (a->ran_paging_area.ran_area_ids[i].ranac_present) + _EQ_CHECK_INT(a->ran_paging_area.ran_area_ids[i].ranac, b->ran_paging_area.ran_area_ids[i].ranac); + } + } + + return true; +} + +/** + * @brief XnAP RAN Paging memory management + */ +void free_xnap_ran_paging(xnap_ran_paging_t *msg) +{ + if (msg->ran_paging_area.choice == XNAP_RAN_PAGING_AREA_CELL_LIST) + free(msg->ran_paging_area.cell_ids); + else + free(msg->ran_paging_area.ran_area_ids); +} diff --git a/openair2/XNAP/lib/xnap_gNB_mobility_management.h b/openair2/XNAP/lib/xnap_gNB_mobility_management.h index 7750fb8570..9ac6df3642 100644 --- a/openair2/XNAP/lib/xnap_gNB_mobility_management.h +++ b/openair2/XNAP/lib/xnap_gNB_mobility_management.h @@ -15,6 +15,7 @@ XNAP_XnAP_PDU_t *encode_xnap_sn_status_transfer(const xnap_sn_status_transfer_t XNAP_XnAP_PDU_t *encode_xnap_ue_context_release(const xnap_ue_context_release_t *msg); XNAP_XnAP_PDU_t *encode_xnap_handover_cancel(const xnap_handover_cancel_t *msg); XNAP_XnAP_PDU_t *encode_xnap_handover_success(const xnap_handover_success_t *msg); +XNAP_XnAP_PDU_t *encode_xnap_ran_paging(const xnap_ran_paging_t *msg); bool decode_xnap_handover_request(xnap_handover_req_t *req, const XNAP_XnAP_PDU_t *pdu); bool decode_xnap_handover_request_acknowledge(xnap_handover_req_ack_t *out, const XNAP_XnAP_PDU_t *pdu); @@ -23,6 +24,7 @@ bool decode_xnap_sn_status_transfer(xnap_sn_status_transfer_t *out, const XNAP_X bool decode_xnap_ue_context_release(xnap_ue_context_release_t *out, const XNAP_XnAP_PDU_t *pdu); bool decode_xnap_handover_cancel(xnap_handover_cancel_t *out, const XNAP_XnAP_PDU_t *pdu); bool decode_xnap_handover_success(xnap_handover_success_t *out, const XNAP_XnAP_PDU_t *pdu); +bool decode_xnap_ran_paging(xnap_ran_paging_t *out, const XNAP_XnAP_PDU_t *pdu); bool eq_xnap_handover_request(const xnap_handover_req_t *a, const xnap_handover_req_t *b); bool eq_xnap_handover_request_acknowledge(const xnap_handover_req_ack_t *a, const xnap_handover_req_ack_t *b); @@ -32,6 +34,7 @@ bool eq_xnap_sn_status_transfer(const xnap_sn_status_transfer_t *a, const xnap_s bool eq_xnap_ue_context_release(const xnap_ue_context_release_t *a, const xnap_ue_context_release_t *b); bool eq_xnap_handover_cancel(const xnap_handover_cancel_t *a, const xnap_handover_cancel_t *b); bool eq_xnap_handover_success(const xnap_handover_success_t *a, const xnap_handover_success_t *b); +bool eq_xnap_ran_paging(const xnap_ran_paging_t *a, const xnap_ran_paging_t *b); void free_xnap_handover_request(xnap_handover_req_t *msg); void free_xnap_handover_request_acknowledge(xnap_handover_req_ack_t *msg); @@ -40,5 +43,6 @@ void free_xnap_sn_status_transfer(xnap_sn_status_transfer_t *msg); void free_xnap_ue_context_release(xnap_ue_context_release_t *msg); void free_xnap_handover_cancel(xnap_handover_cancel_t *msg); void free_xnap_handover_success(xnap_handover_success_t *msg); +void free_xnap_ran_paging(xnap_ran_paging_t *msg); #endif // XNAP_GNB_MOBILITY_MANAGEMENT_H_ diff --git a/openair2/XNAP/lib/xnap_lib_includes.h b/openair2/XNAP/lib/xnap_lib_includes.h index 60bfb55501..011ca44379 100644 --- a/openair2/XNAP/lib/xnap_lib_includes.h +++ b/openair2/XNAP/lib/xnap_lib_includes.h @@ -39,5 +39,15 @@ #include "XNAP_DRBBStatusTransfer18bitsSN.h" #include "XNAP_DRBBStatusTransfer12bitsSN.h" +#include "XNAP_UEIdentityIndexValue.h" +#include "XNAP_UERANPagingIdentity.h" +#include "XNAP_PagingDRX.h" +#include "XNAP_RANPagingArea.h" +#include "XNAP_RANPagingAreaChoice.h" +#include "XNAP_NG-RAN-Cell-Identity-ListinRANPagingArea.h" +#include "XNAP_NG-RAN-Cell-Identity.h" +#include "XNAP_RANAreaID-List.h" +#include "XNAP_RANAreaID.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 0eec420bf4..3c237ad852 100644 --- a/openair2/XNAP/tests/xnap_lib_test.c +++ b/openair2/XNAP/tests/xnap_lib_test.c @@ -726,6 +726,65 @@ static void test_xn_handover_success(void) 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"); @@ -742,6 +801,7 @@ int main() { 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;