XNAP: add encode/decode and unit test for Xn Handover Success

- Add Handover Success message type definitions
- Implement encoder and decoder for Handover Success
    Handover Success (3GPP TS 38.423v16.2.0 §9.1.1.12)
    - Source NG-RAN node UE XnAP ID (M)
    - Target NG-RAN node UE XnAP ID (M)
    - Requested Target Cell Global ID (M)
- Add equality check and memory management helpers
- Extend XNAP library unit tests to cover Handover Success

Reviewed-by: Venkatareddy Akumalla <venkatareddy.akumalla@openairinterface.org>
Signed-off-by: Mohammed Safwan <mohammed.safwan@openairinterface.org>
This commit is contained in:
Mohammed Safwan
2026-06-12 17:44:49 +05:30
parent 7cf0e252b3
commit e7f12fdd61
4 changed files with 160 additions and 0 deletions

View File

@@ -390,4 +390,14 @@ typedef struct {
xnap_cause_t cause;
} xnap_handover_cancel_t;
/* 3GPP TS 38.423 9.1.1.12 Handover Success */
typedef struct {
/* Source NG-RAN node UE XnAP ID (M) */
uint32_t s_ng_node_ue_xnap_id;
/* Target NG-RAN node UE XnAP ID (M) */
uint32_t t_ng_node_ue_xnap_id;
/* Requested Target Cell Global ID (M) */
xnap_ngran_cgi_t target_cgi;
} xnap_handover_success_t;
#endif /* XNAP_MESSAGES_TYPES_H_ */

View File

@@ -1381,3 +1381,110 @@ void free_xnap_handover_cancel(xnap_handover_cancel_t *msg)
// Nothing to free
UNUSED(msg);
}
/**
* @brief XnAP Handover Success encoding
*/
XNAP_XnAP_PDU_t *encode_xnap_handover_success(const xnap_handover_success_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_handoverSuccess;
initMsg->criticality = XNAP_Criticality_ignore;
initMsg->value.present = XNAP_InitiatingMessage__value_PR_HandoverSuccess;
XNAP_HandoverSuccess_t *out = &initMsg->value.choice.HandoverSuccess;
/* Source NG-RAN node UE XnAP ID (M) */
asn1cSequenceAdd(out->protocolIEs.list, XNAP_HandoverSuccess_IEs_t, ie1);
ie1->id = XNAP_ProtocolIE_ID_id_sourceNG_RANnodeUEXnAPID;
ie1->criticality = XNAP_Criticality_reject;
ie1->value.present = XNAP_HandoverSuccess_IEs__value_PR_NG_RANnodeUEXnAPID;
ie1->value.choice.NG_RANnodeUEXnAPID = msg->s_ng_node_ue_xnap_id;
/* Target NG-RAN node UE XnAP ID (M) */
asn1cSequenceAdd(out->protocolIEs.list, XNAP_HandoverSuccess_IEs_t, ie2);
ie2->id = XNAP_ProtocolIE_ID_id_targetNG_RANnodeUEXnAPID;
ie2->criticality = XNAP_Criticality_reject;
ie2->value.present = XNAP_HandoverSuccess_IEs__value_PR_NG_RANnodeUEXnAPID_1;
ie2->value.choice.NG_RANnodeUEXnAPID_1 = msg->t_ng_node_ue_xnap_id;
/* Requested Target Cell Global ID (M) */
asn1cSequenceAdd(out->protocolIEs.list, XNAP_HandoverSuccess_IEs_t, ie3);
ie3->id = XNAP_ProtocolIE_ID_id_requestedTargetCellGlobalID;
ie3->criticality = XNAP_Criticality_reject;
ie3->value.present = XNAP_HandoverSuccess_IEs__value_PR_Target_CGI;
ie3->value.choice.Target_CGI = xnap_encode_target_cgi(&msg->target_cgi);
return pdu;
}
/**
* @brief XnAP Handover Success decoding
*/
bool decode_xnap_handover_success(xnap_handover_success_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_handoverSuccess);
_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, XNAP_InitiatingMessage__value_PR_HandoverSuccess);
XNAP_HandoverSuccess_t *in = &pdu->choice.initiatingMessage->value.choice.HandoverSuccess;
XNAP_HandoverSuccess_IEs_t *ie;
XNAP_LIB_FIND_IE(XNAP_HandoverSuccess_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_sourceNG_RANnodeUEXnAPID, true);
XNAP_LIB_FIND_IE(XNAP_HandoverSuccess_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_targetNG_RANnodeUEXnAPID, true);
XNAP_LIB_FIND_IE(XNAP_HandoverSuccess_IEs_t, ie, &in->protocolIEs.list, XNAP_ProtocolIE_ID_id_requestedTargetCellGlobalID, 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_sourceNG_RANnodeUEXnAPID: {
_EQ_CHECK_INT(ie->value.present, XNAP_HandoverSuccess_IEs__value_PR_NG_RANnodeUEXnAPID);
out->s_ng_node_ue_xnap_id = ie->value.choice.NG_RANnodeUEXnAPID;
} break;
case XNAP_ProtocolIE_ID_id_targetNG_RANnodeUEXnAPID: {
_EQ_CHECK_INT(ie->value.present, XNAP_HandoverSuccess_IEs__value_PR_NG_RANnodeUEXnAPID_1);
out->t_ng_node_ue_xnap_id = ie->value.choice.NG_RANnodeUEXnAPID_1;
} break;
case XNAP_ProtocolIE_ID_id_requestedTargetCellGlobalID: {
_EQ_CHECK_INT(ie->value.present, XNAP_HandoverSuccess_IEs__value_PR_Target_CGI);
if (!xnap_decode_target_cgi(&ie->value.choice.Target_CGI, &out->target_cgi))
return false;
} break;
default:
PRINT_ERROR("XNAP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
return true;
}
/**
* @brief XnAP Handover Success equality function
*/
bool eq_xnap_handover_success(const xnap_handover_success_t *a, const xnap_handover_success_t *b)
{
_EQ_CHECK_UINT32(a->s_ng_node_ue_xnap_id, b->s_ng_node_ue_xnap_id);
_EQ_CHECK_UINT32(a->t_ng_node_ue_xnap_id, b->t_ng_node_ue_xnap_id);
if (!eq_xnap_ngran_cgi(&a->target_cgi, &b->target_cgi))
return false;
return true;
}
/**
* @brief XnAP Handover Success memory management
*/
void free_xnap_handover_success(xnap_handover_success_t *msg)
{
// Nothing to free
UNUSED(msg);
}

View File

@@ -14,6 +14,7 @@ XNAP_XnAP_PDU_t *encode_xnap_handover_preparation_failure(const xnap_handover_pr
XNAP_XnAP_PDU_t *encode_xnap_sn_status_transfer(const xnap_sn_status_transfer_t *sn_status);
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);
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);
@@ -21,6 +22,7 @@ bool decode_xnap_handover_preparation_failure(xnap_handover_preparation_failure_
bool decode_xnap_sn_status_transfer(xnap_sn_status_transfer_t *out, const XNAP_XnAP_PDU_t *pdu);
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 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);
@@ -29,6 +31,7 @@ bool eq_xnap_handover_preparation_failure(const xnap_handover_preparation_failur
bool eq_xnap_sn_status_transfer(const xnap_sn_status_transfer_t *a, const xnap_sn_status_transfer_t *b);
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);
void free_xnap_handover_request(xnap_handover_req_t *msg);
void free_xnap_handover_request_acknowledge(xnap_handover_req_ack_t *msg);
@@ -36,5 +39,6 @@ void free_xnap_handover_preparation_failure(xnap_handover_preparation_failure_t
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);
#endif // XNAP_GNB_MOBILITY_MANAGEMENT_H_

View File

@@ -688,6 +688,44 @@ static void test_xn_handover_cancel(void)
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__);
}
int main() {
printf("Starting XnAP Library Unit Tests...\n");
@@ -703,6 +741,7 @@ int main() {
test_xn_sn_status_transfer();
test_xn_ue_context_release();
test_xn_handover_cancel();
test_xn_handover_success();
printf("All XnAP tests passed!\n");
return 0;