This sample is provided as part of the OSS ASN.1 Tools trial and commercial shipments. The source code and related files are listed below for reference.
The sample demonstrates how to use the OSS ASN.1 Tools to process messages for the 3GPP 5G XnAP standard (TS 38.423 version 19.0.0).
It runs on Linux on x86-64 as an example and illustrates how to decode, inspect, and create PER-encoded 5G XnAP messages using the OSS ASN.1 Tools API.
The sample reads XnAP messages from .per files, decodes and prints them, and creates and encodes a response message.
A makefile is included for building and running the test program using the OSS ASN.1/C++ runtime.
To explore more samples (LTE RRC, 5G RRC, S1AP, X2AP, XnAP), visit the main Sample Code page.
This sample shows how to:
The files listed below are included in the OSS ASN.1 Tools trial and commercial shipments and are used by this sample program:
| File | Description |
|---|---|
| README.TXT | Instructions and sample overview. |
| *.asn | ASN.1 source files that describe the 3GPP 5G XnAP protocol (TS 38.423) used with this program example. |
| XNAP-PDU_HandoverRequest.per | Valid PER-encoded XnAP message. It should pass testing. |
| txnap.cpp | Simple C++ program that shows how to work with 5G XnAP protocol data. It reads input messages from files, decodes and prints them, and creates and encodes a response message. |
| makefile | Makefile that builds and runs the sample test. |
| makefile.rtoed | Makefile that builds and runs the sample test using RTOED. |
| gui/ | ASN.1 Studio project for viewing/compiling schema and generating sample data. |
(Installation instructions for the OSS ASN.1 Tools are included in all trial and commercial shipments.)
To build and run this sample, install a trial or licensed version of the OSS ASN.1 Tools for C++.
If your shipment is runtime-only, generate the .cpp and .h files by running:
make cross
This creates a samples/cross directory with:
make
This command compiles the sample C++ source, links it with the OSS ASN.1 static library, and executes the test. To use another type of library in the shipment (such as a shared library), set the A makefile variable, for example:
make A=so
make clean
Note: The C++ source code in this sample is platform-independent. Linux commands are shown as an example, but equivalent samples and build instructions are available for Windows, macOS, and other platforms. For help with platform-specific instructions, please contact OSS Support.
The following listing shows the main C++ source file for this sample test program, txnap.cpp. It demonstrates how to read PER-encoded 5G XnAP messages from files, decode and print them, and create and encode a response message using the OSS ASN.1 Tools API.
/*****************************************************************************/
/* Copyright (C) ###RELEASE_YEAR### OSS Nokalva, Inc. All rights reserved. */
/*****************************************************************************/
/* THIS FILE IS PROPRIETARY MATERIAL OF OSS NOKALVA, INC. */
/* AND MAY BE USED ONLY BY DIRECT LICENSEES OF OSS NOKALVA, INC. */
/* THIS FILE MAY NOT BE DISTRIBUTED. */
/* THIS COPYRIGHT STATEMENT MAY NOT BE REMOVED. */
/* THIS SAMPLE PROGRAM IS PROVIDED AS IS. THE SAMPLE PROGRAM AND ANY RESULTS */
/* OBTAINED FROM IT ARE PROVIDED WITHOUT ANY WARRANTIES OR REPRESENTATIONS, */
/* EXPRESS, IMPLIED OR STATUTORY. */
/*****************************************************************************/
/*
*Demonstrates work with data for XNAP protocol
*/
#include <errno.h>
#include <string.h>
#include "xnap_r19.h"
/* Names of Criticality values */
static const char *Criticalities[] = { "reject", "ignore", "notify" };
/* The directory where input files reside. It is set to the command line parameter
* if any and to the directory where the sample is started, otherwise.
*/
char *filesDir;
/*
* FUNCTION Helper function to open file in the specified directory.
*
* PARAMETERS
* directoryName directory where fileName resides
* fileName file to open
*
* RETURNS pointer to file on success, NULL on failure
*/
FILE * openInputFile(char *directoryName, const char *fileName)
{
char *path;
FILE *fv;
const char kPathSeparator =
#ifdef _WIN32
'\\';
#else
'/';
#endif
if (directoryName) {
size_t dLength = strlen(directoryName);
if (NULL == (path = (char*)asn1Malloc(dLength + strlen(fileName) + 2))) {
return NULL;
}
memcpy(path, directoryName, dLength);
if (path[dLength - 1] != kPathSeparator)
path[dLength++] = kPathSeparator;
strcpy(path+dLength, fileName);
} else {
path = (char *) fileName;
}
if (!(fv = fopen(path, "rb"))) {
printf("Failed to open the '%s' file. Restart the sample program using the file "
"location as the input parameter.\n", path);
}
if (path != fileName)
asn1Free(path);
return fv;
}
/*
* FUNCTION readEncodingFromFile() reads serialized message from specified
* file
*
* PARAMETERS
* filename name of file containing serialized message
* buf read message
*
* RETURNS 0 on success, error code on failure
*/
static int readEncodingFromFile(const char *filename, EncodedBuffer &buf)
{
FILE *in = openInputFile(filesDir, filename);
long length;
char *data;
if (!in) {
printf("fopen() failed to open %s: %s\n", filename, strerror(errno));
exit(-1);
}
if (fseek(in, 0, SEEK_END)) {
printf("fseek() failed: %s\n", strerror(errno));
exit(-1);
}
length = ftell(in);
if (length < 0) {
printf("ftell() failed: %s\n", strerror(errno));
exit(-1);
}
/* Allocate memory to store completely read message in it */
data = (char*)asn1Malloc(length);
rewind(in);
if ((size_t)length != fread(data, sizeof(char), (size_t)length, in)) {
printf("fread() failed\n");
}
fclose(in);
/* Store read message in output argument */
buf.grab_buffer(length, data);
return 0;
}
/*****************************************************************************
* Printing functions below are intended to demonstrate how to access NGAP
* PDU components and to analyze their contents.
*****************************************************************************/
/*
* FUNCTION printHexString() prints data (octet string) as a sequence of
* hexadecimal digits 'XXXX...'H
*
* PARAMETERS
* length length of input data
* value pointer to input data
* indent indentation
*
*/
static void printHexString(unsigned int length, unsigned char *value, int indent)
{
unsigned int i, j,
max_pos = 74 - indent;
printf("'");
for (i = 0, j = 1; i < length; i++, j += 2) {
/* skip to next line when the current one is filled */
if (j >= max_pos) {
printf("'\n%*s'", indent, "");
j = 1;
}
printf("%02X", value[i]);
}
printf("'H");
}
/* Prints a BIT STRING as a sequence of hexadecimal digits */
#define printHexBitString(length, value, indent)\
printHexString((length + 7)/8, value, indent)
/*
* FUNCTION printProtocolExtensions() prints ProtocolExtensionContainer
* data.
*
* PARAMETERS
* ctl OSS environment variable
* ie_ext pointer to ProtocolExtensionContainer data to print
* indent indentation
*
* RETURNS 0 on success, error code on failure
*/
static int printProtocolExtensions(OssControl &ctl,
OSS_XNAP_NR_CGI::iE_Extension *ie_ext, int indent)
{
if (!ie_ext)
return 0;
printf("%*s%s includes the following IEs:\n", indent++, "",
"iE-Extensions");
int cnt = 0;
/* Print each IE in the list */
for (OssIndex i = ie_ext->first(); i != OSS_NOINDEX; i = ie_ext->next(i)) {
OSS_XNAP_UESecurityCapabilities_ExtIEs_Extension &extval = ie_ext->at(i)->get_extensionValue();
printf("%*s#%d: id = %2u, criticality = %s\n", indent, "",
cnt++, ie_ext->at(i)->get_id(), Criticalities[ie_ext->at(i)->get_criticality()]);
if (extval.has_decoded()) {
OSS_XNAP_PDU_PDU pdu;
extval.get_decoded(pdu);
pdu.print(ctl);
} else {
printf("PDU is not decoded\n");
}
}
return 0;
}
/*
* FUNCTION printProtocolExtensionsGTPTransportLayer() prints ProtocolExtensionContainer
* data.
*
* PARAMETERS
* ctl OSS environment variable
* ie_ext pointer to ProtocolExtensionContainer data to print
* indent indentation
*
* RETURNS 0 on success, error code on failure
*/
static int printProtocolExtensionsGTPTransportLayer(OssControl &ctl,
OSS_XNAP_GTPtunnelTransportLayerInformation::iE_Extensions *ie_ext, int indent)
{
if (!ie_ext)
return 0;
printf("%*s%s includes the following IEs:\n", indent++, "",
"iE-Extensions");
int cnt = 0;
/* Print each IE in the list */
for (OssIndex i = ie_ext->first(); i != OSS_NOINDEX; i = ie_ext->next(i)) {
OSS_XNAP_GTPtunnelTransportLayerInformation_ExtIEs_Extension &extval = ie_ext->at(i)->get_extensionValue();
printf("%*s#%d: id = %2u, criticality = %s\n", indent, "",
cnt++, ie_ext->at(i)->get_id(), Criticalities[ie_ext->at(i)->get_criticality()]);
if (extval.has_decoded()) {
OSS_XNAP_PDU_PDU pdu;
extval.get_decoded(pdu);
pdu.print(ctl);
} else {
printf("PDU is not decoded\n");
}
}
return 0;
}
/*
* FUNCTION printProtocolExtensions7() prints ProtocolExtensionContainer
* data.
*
* PARAMETERS
* ctl OSS environment variable
* ie_ext pointer to ProtocolExtensionContainer data to print
* indent indentation
*
* RETURNS 0 on success, error code on failure
*/
static int printProtocolExtensions7(OssControl &ctl,
OSS_XNAP_UEContextInfoHORequest::iE_Extensions *ie_ext,
int indent)
{
if (!ie_ext)
return 0;
printf("%*s%s includes the following IEs:\n", indent++, "",
"iE-Extensions");
int cnt = 0;
/* Print each IE in the list */
for (OssIndex i = ie_ext->first(); i != OSS_NOINDEX; i = ie_ext->next(i)) {
OSS_XNAP_UEContextInfoHORequest_ExtIEs_Extension &extval = ie_ext->at(i)->get_extensionValue();
printf("%*s#%d: id = %2u, criticality = %s\n", indent, "",
cnt++, ie_ext->at(i)->get_id(), Criticalities[ie_ext->at(i)->get_criticality()]);
if (extval.has_decoded()) {
OSS_XNAP_PDU_PDU pdu;
extval.get_decoded(pdu);
pdu.print(ctl);
} else {
printf("PDU is not decoded\n");
}
}
return 0;
}
/*
* FUNCTION printProtocolIEs() prints ProtocolIE_Container data.
* ossPrintPDU() is called to print IEs that are not
* handled by this function.
*
* PARAMETERS
* ctl OssControl object
* ies pointer to ProtocolIE-Container data to print
* indent indentation
*
* RETURNS 0 on success, error code on failure
*/
static int printProtocolIEs(OssControl &ctl, OSS_XNAP_HRequestIEs &ies, int indent)
{
int err = 0;
printf("%*s%s includes the following IEs:\n", indent++, "",
"protocolIEs");
/* Print each IE */
int i = 1;
for (OssIndex idx = ies.first(); idx != OSS_NOINDEX; idx = ies.next(idx), i++) {
OSS_XNAP_HRequestIE *field = ies.at(idx);
OSS_XNAP_HandoverRequest_IEs_Value &value = field->get_value();
printf("\n%*s#%d: id = %2u, criticality = %s\n", indent, "",
i, field->get_id(), Criticalities[field->get_criticality()]);
++indent;
if (field->get_id() == OSS_XNAP_id_sourceNG_RANnodeUEXnAPID) {
printf("%*svalue %s: %u", indent, "", "NG-RANnodeUEXnAPID",
*value.get_OSS_XNAP_NG_RANnodeUEXnAPID());
} else if (field->get_id() == OSS_XNAP_id_Cause) {
OSS_XNAP_Cause *pcause = value.get_OSS_XNAP_Cause();
/*
* Named values can be printed below instead of numbers for all
* Cause components
*/
printf("%*svalue %s: ", indent, "", "Cause");
if (pcause->get_radioNetwork()) {
printf("%s : %d", "radioNetwork", *pcause->get_radioNetwork());
} else if (pcause->get_transport()) {
printf("%s : %d", "transport", *pcause->get_transport());
} else if (pcause->get_protocol()) {
printf("%s : %d", "protocol", *pcause->get_protocol());
} else if (pcause->get_misc()) {
printf("%s : %d", "misc", *pcause->get_misc());
} else if (pcause->get_choice_extension()) {
printf("choice-extension: -- Not implemented --");
}
} else if (field->get_id() == OSS_XNAP_id_targetCellGlobalID) {
OSS_XNAP_Target_CGI *tvalue = value.get_OSS_XNAP_Target_CGI();
printf("%*svalue %s: ", indent, "", "Target-CGI");
if (tvalue->get_nr()) {
OSS_XNAP_NR_CGI *nr = tvalue->get_nr();
printf("%s:\n", "nr");
++indent;
printf("%*s%s: ", indent, "", "plmn-id");
printHexString(nr->get_plmn_id().length(),
(unsigned char*)nr->get_plmn_id().get_buffer(),
indent);
printf("\n%*s%s: ", indent, "", "nr-CI");
printHexBitString(nr->get_nr_CI().length(), nr->get_nr_CI().get_buffer(), indent);
--indent;
} else if (tvalue->get_e_utra()) {
OSS_XNAP_E_UTRA_CGI *e_utra = tvalue->get_e_utra();
printf("%*s%s: \n", indent, "", "e-utra");
++indent;
printf("%*s%s: ", indent, "", "plmn-id");
printHexString(e_utra->get_plmn_id().length(),
(unsigned char*)e_utra->get_plmn_id().get_buffer(), indent);
printf("\n%*s%s: ", indent, "", "e-utra-CI");
printHexBitString(e_utra->get_e_utra_CI().length(), e_utra->get_e_utra_CI().get_buffer(), indent);
if (e_utra->get_iE_Extension()) {
printf("\n%*s%s: ", indent, "", "iE-Extension");
printProtocolExtensions(ctl, e_utra->get_iE_Extension(), indent);
}
--indent;
} else if (tvalue->get_choice_extension()) {
printf("choice-extension: -- Not implemented --");
}
} else if (field->get_id() == OSS_XNAP_id_GUAMI) {
OSS_XNAP_GUAMI *gvalue = value.get_OSS_XNAP_GUAMI();
printf("%*svalue %s: ", indent, "", "GUAMI");
++indent;
printf("%*s%s: ", indent, "", "plmn-ID");
printHexString(gvalue->get_plmn_ID().length(),
(unsigned char*)gvalue->get_plmn_ID().get_buffer(), indent);
printf("\n%*s%s: ", indent, "", "amf-region-if");
printHexBitString(gvalue->get_amf_region_id().length(),\
gvalue->get_amf_region_id().get_buffer(), indent);
printf("\n%*s%s: ", indent, "", "amf-set-id");
printHexBitString(gvalue->get_amf_set_id().length(),\
gvalue->get_amf_set_id().get_buffer(), indent);
printf("\n%*s%s: ", indent, "", "amf-pointer");
printHexBitString(gvalue->get_amf_pointer().length(),\
gvalue->get_amf_pointer().get_buffer(), indent);
if (gvalue->get_iE_Extensions()) {
printf("\n%*s%s: ", indent, "", "iE-Extensions");
printProtocolExtensions(ctl, gvalue->get_iE_Extensions(), indent);
}
--indent;
} else if (field->get_id() == OSS_XNAP_id_UEContextInfoHORequest) {
OSS_XNAP_UEContextInfoHORequest *rvalue = value.get_OSS_XNAP_UEContextInfoHORequest();
printf("%*svalue %s: ", indent, "", "UEContextInfoHORequest");
++indent;
printf("\n%*s%s: %llu", indent, "", "ng-c-UE-reference",
rvalue->get_ng_c_UE_reference());
printf("\n%*s%s: ", indent, "", "cp-TNL-info-source");
OSS_XNAP_CPTransportLayerInformation &el = rvalue->get_cp_TNL_info_source();
if (el.get_endpointIPAddress()) {
printf("%s : ", "endpointIPAddress");
printHexBitString(el.get_endpointIPAddress()->length(),\
el.get_endpointIPAddress()->get_buffer(), indent);
} else if (el.get_choice_extension()) {
printf("choice-extension: -- Not implemented --");
}
printf("\n%*s%s: ", indent, "", "ueSecurityCapabilities");
++indent;
OSS_XNAP_UESecurityCapabilities &secc = rvalue->get_ueSecurityCapabilities();
printf("\n%*s%s: ", indent, "", "nr-EncyptionAlgorithms");
printHexBitString(secc.get_nr_EncyptionAlgorithms().length(),\
secc.get_nr_EncyptionAlgorithms().get_buffer(), indent);
printf("\n%*s%s: ", indent, "", "nr-IntegrityProtectionAlgorithms");
printHexBitString(secc.get_nr_IntegrityProtectionAlgorithms().length(),\
secc.get_nr_IntegrityProtectionAlgorithms().get_buffer(), indent);
printf("\n%*s%s: ", indent, "", "e-utra-EncyptionAlgorithms");
printHexBitString(secc.get_e_utra_EncyptionAlgorithms().length(),\
secc.get_e_utra_EncyptionAlgorithms().get_buffer(), indent);
printf("\n%*s%s: ", indent, "", "e-utra-IntegrityProtectionAlgorithms");
printHexBitString(secc.get_e_utra_IntegrityProtectionAlgorithms().length(),\
secc.get_e_utra_IntegrityProtectionAlgorithms().get_buffer(), indent);
if (secc.get_iE_Extension()) {
printf("\n%*s%s: ", indent, "", "iE-Extension");
printProtocolExtensions(ctl, secc.get_iE_Extension(), indent);
}
--indent;
printf("\n%*s%s: ", indent, "", "securityInformation");
++indent;
printf("\n%*s%s: ", indent, "", "key-NG-RAN-Star");
printHexBitString(rvalue->get_securityInformation().get_key_NG_RAN_Star().length(),\
rvalue->get_securityInformation().get_key_NG_RAN_Star().get_buffer(), indent);
printf("\n%*s%s: %d", indent, "", "ncc",
rvalue->get_securityInformation().get_ncc());
if (rvalue->get_securityInformation().get_iE_Extensions()) {
printf("\n%*s%s: ", indent, "", "iE-Extensions");
printProtocolExtensions(ctl, rvalue->get_securityInformation().get_iE_Extensions(), indent);
}
--indent;
if (rvalue->get_indexToRatFrequencySelectionPriority()) {
printf("\n%*s%s: %d", indent, "", "indexToRatFrequencySelectionPriority",
*rvalue->get_indexToRatFrequencySelectionPriority());
}
printf("\n%*s%s: ", indent, "", "ue-AMBR");
++indent;
printf("\n");
printf("%*s%s: " LLONG_FMT, indent, "", "dl-UE-AMBR",
rvalue->get_ue_AMBR().get_dl_UE_AMBR());
printf(" \n%*s%s: " LLONG_FMT, indent, "", "ul-UE-AMBR",
rvalue->get_ue_AMBR().get_ul_UE_AMBR());
if (rvalue->get_ue_AMBR().get_iE_Extension()) {
printf("\n%*s%s: ", indent, "", "iE_Extension");
printProtocolExtensions(ctl, rvalue->get_ue_AMBR().get_iE_Extension(), indent);
}
--indent;
OSS_XNAP_UEContextInfoHORequest::pduSessionResourcesToBeSetup_List &list =
rvalue->get_pduSessionResourcesToBeSetup_List();
printf("\n%*s%s: ", indent, "", "pduSessionResourcesToBeSetup-List");
++indent;
int j = 1;
for (OssIndex li = list.first(); li; j++, li = list.next(li)) {
printf("\n%*s#%d:", indent, "", j);
++indent;
printf("\n%*s%s: %d", indent, "", "pduSessionId",
list.at(li)->get_pduSessionId());
printf("\n%*s%s: ", indent, "", "s-NSSAI");
++indent;
printf("\n%*s%s: ", indent, "", "sst");
printHexString(list.at(li)->get_s_NSSAI().get_sst().length(),
(unsigned char*)list.at(li)->get_s_NSSAI().get_sst().get_buffer(), indent);
if (list.at(li)->get_s_NSSAI().get_sd()) {
printf("\n%*s%s: ", indent, "", "sd");
printHexString(list.at(li)->get_s_NSSAI().get_sd()->length(),
(unsigned char*)list.at(li)->get_s_NSSAI().get_sd()->get_buffer(), indent);
}
if (list.at(li)->get_s_NSSAI().get_iE_Extensions()) {
printf("\n%*s%s: ", indent, "", "iE-Extensions");
printProtocolExtensions(ctl, list.at(li)->get_s_NSSAI().get_iE_Extensions(), indent);
}
--indent;
printf("\n%*s%s: ", indent, "", "pduSessionAMBR");
++indent;
printf("\n%*s%s: " LLONG_FMT, indent, "", "downlink-session-AMBR",
list.at(li)->get_pduSessionAMBR()->get_downlink_session_AMBR());
printf("\n%*s%s: " LLONG_FMT, indent, "", "uplink-session-AMBR",
list.at(li)->get_pduSessionAMBR()->get_uplink_session_AMBR());
if (list.at(li)->get_pduSessionAMBR()->get_iE_Extensions()) {
printf("\n%*s%s: ", indent, "", "iE-Extensions");
printProtocolExtensions(ctl, list.at(li)->get_pduSessionAMBR()->get_iE_Extensions(), indent);
}
--indent;
printf("\n%*s%s: ", indent, "", "uL-NG-U-TNLatUPF");
++indent;
if (list.at(li)->get_uL_NG_U_TNLatUPF().get_gtpTunnel()) {
printf("%s: ", "gtpTunnel");
++indent;
printf("\n%*s%s: ", indent, "", "tnl-address");
printHexBitString(
list.at(li)->get_uL_NG_U_TNLatUPF().get_gtpTunnel()->get_tnl_address().length(), \
(unsigned char*)list.at(li)->get_uL_NG_U_TNLatUPF().get_gtpTunnel()->get_tnl_address().get_buffer(), \
indent);
printf("\n%*s%s: ", indent, "", "gtp-teid");
printHexString(list.at(li)->get_uL_NG_U_TNLatUPF().get_gtpTunnel()->get_gtp_teid().length(),
(unsigned char*)list.at(li)->get_uL_NG_U_TNLatUPF().get_gtpTunnel()->get_gtp_teid().get_buffer(),
indent);
if (list.at(li)->get_uL_NG_U_TNLatUPF().get_gtpTunnel()->get_iE_Extensions()) {
printf("\n%*s%s: ", indent, "", "iE-Extensions");
printProtocolExtensionsGTPTransportLayer(ctl,
list.at(li)->get_uL_NG_U_TNLatUPF().get_gtpTunnel()->get_iE_Extensions(),
indent);
}
--indent;
} else if (list.at(li)->get_uL_NG_U_TNLatUPF().get_choice_extension()) {
printf("choice-extension: -- Not implemented --");
}
--indent;
if (list.at(li)->get_securityIndication()) {
printf("\n%*s%s", indent, "", "securityIndication: -- Not implemented --");
}
printf("\n%*s%s: %d", indent, "", "pduSessionType", list.at(li)->get_pduSessionType());
printf("\n%*s%s:", indent, "", "qosFlowsToBeSetup-List");
OSS_XNAP_QoSFlowsToBeSetup_List &qos_list = list.at(li)->get_qosFlowsToBeSetup_List();
int k = 1;
for (OssIndex qidx = qos_list.first(); qidx; k++, qidx = qos_list.next(qidx)) {
printf("\n%*s#%d:", indent, "", k);
++indent;
printf("\n%*s%s: %ld", indent, "", "qfi", (long)qos_list.at(qidx)->get_qfi());
printf("\n%*s%s", indent, "", "qosFlowLevelQoSParameters: -- Not implemented --");
--indent;
}
--indent;
}
--indent;
printf("\n%*s%s: ", indent, "", "rrc-Context");
printHexString(rvalue->get_rrc_Context().length(),
(unsigned char*)rvalue->get_rrc_Context().get_buffer(), indent);
if (rvalue->get_locationReportingInformation()) {
printf("\n%*s%s", indent, "", "locationReportingInformation: -- Not implemented --");
}
if (rvalue->get_mrl()) {
printf("\n%*s%s: ", indent, "", "mrl: -- Not implemented --");
}
if (rvalue->get_iE_Extensions()) {
printf("\n%*s%s: ", indent, "", "iE-Extensions");
printProtocolExtensions7(ctl, rvalue->get_iE_Extensions(), indent);
}
--indent;
} else if (field->get_id() == OSS_XNAP_id_TraceActivation) {
OSS_XNAP_TraceActivation *tvalue = value.get_OSS_XNAP_TraceActivation();
printf("%*svalue %s:", indent, "", "TraceActivation");
++indent;
printf("\n%*s%s: ", indent, "", "ng-ran-TraceID");
printHexString(tvalue->get_ng_ran_TraceID().length(),\
(unsigned char*)tvalue->get_ng_ran_TraceID().get_buffer(), indent);
printf("\n%*s%s: ", indent, "", "interfaces-to-trace");
printHexBitString(tvalue->get_interfaces_to_trace().length(),\
(unsigned char*)tvalue->get_interfaces_to_trace().get_buffer(), indent);
printf("\n%*s%s: %d", indent, "", "trace-depth",
tvalue->get_trace_depth());
printf("\n%*s%s: ", indent, "", "trace-coll-address");
printHexBitString(tvalue->get_trace_coll_address().length(),\
(unsigned char*)tvalue->get_trace_coll_address().get_buffer(), indent);
if (tvalue->get_ie_Extension()) {
printf("\n%*s%s: ", indent, "", "ie-Extension");
printProtocolExtensions(ctl, (OSS_XNAP_NR_CGI::iE_Extension *)tvalue->get_ie_Extension(), indent);
}
--indent;
} else if (field->get_id() == OSS_XNAP_id_MaskedIMEISV) {
OSS_XNAP_MaskedIMEISV *mvalue = value.get_OSS_XNAP_MaskedIMEISV();
printf("%*svalue %s:\n", indent, "", "MaskedIMEISV");
++indent;
printHexBitString(mvalue->length(), (unsigned char*)mvalue->get_buffer(), indent);
--indent;
} else if (field->get_id() == OSS_XNAP_id_UEHistoryInformation) {
OSS_XNAP_UEHistoryInformation *uvalue = value.get_OSS_XNAP_UEHistoryInformation();
int i = 1;
printf("%*svalue %s:\n", indent, "", "UEHistoryInformation");
++indent;
for (OssIndex ui = uvalue->first(); ui; ui = uvalue->next(ui), i++) {
OSS_XNAP_LastVisitedCell_Item *c = uvalue->at(ui);
if (c->get_nG_RAN_Cell()) {
printf("%*s#%d %s: ", indent, "", i, "nG-RAN-Cell");
printHexString(c->get_nG_RAN_Cell()->length(),\
(unsigned char*)c->get_nG_RAN_Cell()->get_buffer(), indent);
} else if (c->get_e_UTRAN_Cell()) {
printf("%*s#%d %s: ", indent, "", i, "e-UTRAN-Cell");
printHexString(c->get_e_UTRAN_Cell()->length(),\
(unsigned char*)c->get_e_UTRAN_Cell()->get_buffer(), indent);
} else if (c->get_uTRAN_Cell()) {
printf("%*s#%d %s: ", indent, "", i, "uTRAN-Cell");
printHexString(c->get_uTRAN_Cell()->length(),\
(unsigned char*)c->get_uTRAN_Cell()->get_buffer(), indent);
} else if (c->get_gERAN_Cell()) {
printf("%*s#%d %s: ", indent, "", i, "gERAN-Cell");
printHexString(c->get_gERAN_Cell()->length(),\
(unsigned char*)c->get_gERAN_Cell()->get_buffer(), indent);
} else if (c->get_choice_extension()) {
printf("%*s#%d %s", indent, "", i, "choice-extension: -- Not implemented --");
}
printf("\n");
}
--indent;
} else if (field->get_id() == OSS_XNAP_id_UEContextRefAtSN_HORequest) {
OSS_XNAP_UEContextRefAtSN_HORequest *uvalue =
value.get_OSS_XNAP_UEContextRefAtSN_HORequest();
printf("%*svalue %s: ", indent, "", "UEContextRefAtSN-HORequest");
++indent;
printf("\n%*s%s: ", indent, "", "globalNG-RANNode-ID");
OSS_XNAP_GlobalNG_RANNode_ID &el = uvalue->get_globalNG_RANNode_ID();
if (el.get_gNB()) {
printf("gNB: -- Not implemented --");
} else if (el.get_ng_eNB()) {
printf("ng-eNB: -- Not implemented --");
} else if (el.get_choice_extension()) {
printf("choice-extension: -- Not implemented --");
}
printf("\n%*s%s: %d", indent, "", "sN-NG-RANnodeUEXnAPID",
uvalue->get_sN_NG_RANnodeUEXnAPID());
if (uvalue->get_iE_Extensions()) {
printf("\n%*s%s: ", indent, "", "iE-Extensions");
printProtocolExtensions(ctl, uvalue->get_iE_Extensions(), indent);
}
--indent;
}
printf("\n");
--indent;
}
return err;
}
/*
* FUNCTION printHandoverRequestMsg() prints XNAP pdu which contains
* HandoverRequest message. The function is not intended to
* handle other types of messages.
*
* PARAMETERS
* ctl OssControl object
* pdu input XNAP PDU which data should be printed
*
* RETURNS 0 on success, error code on failure
*/
static int printHandoverRequestMsg(OssControl &ctl, OSS_XNAP_PDU *pdu)
{
/* Get identifier of message stored in PDU */
if (!pdu->get_initiatingMessage()) {
printf("Unexpected type of message");
return -1;
}
OSS_XNAP_XNAP_ELEMENTARY_PROCEDURES_InitiatingMessage &msg_value =
pdu->get_initiatingMessage()->get_value();
OSS_XNAP_HandoverRequest *hr_value = msg_value.get_OSS_XNAP_HandoverRequest();
if (!hr_value) {
printf("Unexpected message \n");
return -1;
}
printf("HandoverRequest message:\n\n");
return printProtocolIEs(ctl, hr_value->get_protocolIEs(), 0);
}
/*
* FUNCTION createSuccessResponse() creates XNAP successful outcome
* message for given HandoverRequest request.
*
* PARAMETERS
* world OssControl object
* req input message (request)
* resp pointer to the successful outcome message (response)
* created by the function
*
* RETURNS 0 on success, error code on failure
*/
static int createSuccessResponse(OssControl &ctl, OSS_XNAP_PDU *req,
OSS_XNAP_PDU &resp)
{
OSS_XNAP_PDUSessionResourcesAdmitted_List a_list;
OSS_XNAP_InitiatingMessage * initMsg = req->get_initiatingMessage();
if (!initMsg) {
printf("Unexpected type of message");
return -1;
}
OSS_XNAP_HandoverRequest *hr_value = initMsg->get_value().get_OSS_XNAP_HandoverRequest();
if (!hr_value) {
printf("No HandoverRequest request data");
return -1;
}
OSS_XNAP_HRequestIEs &reqies = hr_value->get_protocolIEs();
/*
* Create successful outcome message from initiating message. Copy
* some IEs from input to output.
*/
OSS_XNAP_SuccessfulOutcome outcome_msg;
outcome_msg.set_procedureCode(initMsg->get_procedureCode());
outcome_msg.set_criticality(OSS_XNAP_reject);
OSS_XNAP_XNAP_ELEMENTARY_PROCEDURES_SuccessfulOutcome ot_val;
OSS_XNAP_HandoverRequestAcknowledge hrk;
OSS_XNAP_HAcknowledgeIEs respies;
for (OssIndex idx = reqies.first(); idx; idx = reqies.next(idx)) {
if (reqies.at(idx)->get_id() == OSS_XNAP_id_sourceNG_RANnodeUEXnAPID) {
OSS_XNAP_HAcknowledgeIE haie;
haie.set_criticality(OSS_XNAP_ignore);
haie.set_id(reqies.at(idx)->get_id());
OSS_XNAP_HandoverRequestAcknowledge_IEs_Value hriesv;
OSS_XNAP_NG_RANnodeUEXnAPID ranuexapid = *reqies.at(idx)->get_value().get_OSS_XNAP_NG_RANnodeUEXnAPID();
hriesv.set_OSS_XNAP_NG_RANnodeUEXnAPID(ranuexapid);
haie.set_value(hriesv);
respies.prepend(haie);
}
}
OssIndex respies_idx = respies.first();
OSS_XNAP_HAcknowledgeIE ie_field;
ie_field.set_id(OSS_XNAP_id_targetNG_RANnodeUEXnAPID);
ie_field.set_criticality(OSS_XNAP_ignore);
OSS_XNAP_HandoverRequestAcknowledge_IEs_Value ot_val2;
ot_val2.set_OSS_XNAP_NG_RANnodeUEXnAPID(456);
ie_field.set_value(ot_val2);
respies_idx = respies.insert_after(respies_idx, ie_field);
/* Add OSS_XNAP_PDUSessionResourcesAdmitted_List IE to outcome message */
ie_field.set_id(OSS_XNAP_id_PDUSessionResourcesAdmitted_List);
ie_field.set_criticality(OSS_XNAP_ignore);
OSS_XNAP_HandoverRequestAcknowledge_IEs_Value hriesv;
OSS_XNAP_PDUSessionResourcesAdmitted_List sral;
OSS_XNAP_PDUSessionResourcesAdmitted_Item a_list_item;
a_list_item.set_pduSessionId(1);
OSS_XNAP_PDUSessionResourceAdmittedInfo pdusrai;
OSS_XNAP_PDUSessionResourceAdmittedInfo::qosFlowsAdmitted_List qosfa_list;
OSS_XNAP_QoSFlowsAdmitted_Item qosfai;
qosfai.set_qfi(4);
qosfa_list.prepend(qosfai);
qosfai.set_qfi(3);
qosfa_list.prepend(qosfai);
OSS_XNAP_PDUSessionResourceAdmittedInfo::qosFlowsNotAdmitted_List qosfna_list;
OSS_XNAP_QoSFlowwithCause_Item qosfnai;
OSS_XNAP_Cause cause;
qosfnai.set_qfi(5);
cause.set_misc(OSS_XNAP_CauseMisc_unspecified);
qosfnai.set_cause(cause);
qosfna_list.prepend(qosfnai);
qosfnai.set_qfi(2);
cause.set_misc(OSS_XNAP_CauseMisc_unspecified);
qosfnai.set_cause(cause);
qosfna_list.prepend(qosfnai);
pdusrai.set_qosFlowsAdmitted_List(qosfa_list);
pdusrai.set_qosFlowsNotAdmitted_List(qosfna_list);
a_list_item.set_pduSessionResourceAdmittedInfo(pdusrai);
sral.prepend(a_list_item);
ot_val2.set_OSS_XNAP_PDUSessionResourcesAdmitted_List(sral);
ie_field.set_value(ot_val2);
respies_idx = respies.insert_after(respies_idx, ie_field);
hrk.set_protocolIEs(respies);
ot_val.set_OSS_XNAP_HandoverRequestAcknowledge(hrk);
outcome_msg.set_value(ot_val);
resp.set_successfulOutcome(outcome_msg);
return 0;
}
/*
* FUNCTION testXNAP() is used to test XNAP message, the input serialized
* pdu is deserialized and printed, then an outcome message
* is created, printed and encoded.
*
* PARAMETERS
* ctl OssControl object
* filename name of file containing serialized message
*
* RETURNS 0 on success, error code on failure
*/
static int testXNAP(OssControl &ctl, const char *filename)
{
EncodedBuffer encoded_data;
int err;
printf("======================================================"
"======================\n");
printf("### Reading serialized request message from file: \"%s\"... ", filename);
/* Read serialized message from file */
err = readEncodingFromFile(filename, encoded_data);
if (!err) {
printf("OK.\n\n");
/*
* Zero deserilaized message pointer in order to allocate it
* in API call
*/
OSS_XNAP_PDU_PDU pdu;
printf("### Deserializing the message...\n");
/* Deserialize input message */
pdu.decode(ctl, encoded_data);
printf("\n");
printf("### Printing the deserialized message:\n");
/* Print deserialized message */
pdu.print(ctl);
printf("\n");
OSS_XNAP_PDU *decoded = pdu.get_data();
printf("### Printing the deserialized message by a handwritten code"
" demonstrating how to access data:\n");
if (0 == (err = printHandoverRequestMsg(ctl, decoded))) {
OSS_XNAP_PDU resp;
printf("\n### Creating Success Response message... ");
/* Create successful outcome message */
err = createSuccessResponse(ctl, pdu.get_data(), resp);
if (!err) {
printf("OK.\n\n### Printing the created response message:\n");
OSS_XNAP_PDU_PDU resp_pdu;
resp_pdu.set_data(resp);
resp_pdu.print(ctl);
printf("\n\n### Serializing the response message... \n");
/* Serialize outcome message */
EncodedBuffer msg;
resp_pdu.encode(ctl, msg);
printf("\n");
printf("Serialized response (%lu bytes):\n",
msg.get_data_size());
printHexString(msg.get_data_size(), (unsigned char*)msg.get_data(), 0);
printf("\n\n");
}
}
pdu.free_data(ctl);
}
return err;
}
/*
* Deserializes and prints input messages, creates and prints successful
* outcome messages
*/
int main(int argc, char *argv[])
{
int err = 0;
try {
_oss_xnap_control_table_Control ctl;
/* Set flags */
ctl.setEncodingFlags(AUTOMATIC_ENCDEC);
ctl.setDecodingFlags(AUTOMATIC_ENCDEC);
/* Set debug mode */
ctl.setDebugFlags(PRINT_ERROR_MESSAGES | PRINT_DECODING_DETAILS |
PRINT_ENCODING_DETAILS);
filesDir = argc > 1 ? argv[1] : (char*)".";
testXNAP(ctl, "XNAP-PDU_HandoverRequest.per");
printf("Testing successful.\n");
} catch (ASN1RuntimeException &exc) {
err = exc.get_code();
printf("An error occurred: code = %d.\n", err);
} catch (...) {
printf("An unexpected exception occurred.\n");
err = -1;
}
return err;
}
This is the expected output when running the sample:
Decoded XnAP message: ... Encoding response message... Encoding successful.
-- Excerpt from ngap.asn 3GPP TS 38.423 V19.0.0 (2025-09)
-- **************************************************************
--
-- **************************************************************
--
-- Elementary Procedure definitions
--
-- **************************************************************
XnAP-PDU-Descriptions {
itu-t (0) identified-organization (4) etsi (0) mobileDomain (0)
ngran-access (22) modules (3) xnap (2) version1 (1) xnap-PDU-Descriptions (0) }
DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
-- **************************************************************
--
-- IE parameter types from other modules.
--
-- **************************************************************
IMPORTS
Criticality,
ProcedureCode
FROM XnAP-CommonDataTypes
HandoverRequest,
HandoverRequestAcknowledge,
HandoverPreparationFailure,
SNStatusTransfer,
UEContextRelease,
HandoverCancel,
NotificationControlIndication,
RANPaging,
RetrieveUEContextRequest,
RetrieveUEContextResponse,
RetrieveUEContextConfirm,
RetrieveUEContextFailure,
XnUAddressIndication,
SecondaryRATDataUsageReport,
SNodeAdditionRequest,
SNodeAdditionRequestAcknowledge,
SNodeAdditionRequestReject,
SNodeReconfigurationComplete,
SNodeModificationRequest,
SNodeModificationRequestAcknowledge,
SNodeModificationRequestReject,
SNodeModificationRequired,
SNodeModificationConfirm,
SNodeModificationRefuse,
SNodeReleaseRequest,
SNodeReleaseRequestAcknowledge,
SNodeReleaseReject,
SNodeReleaseRequired,
SNodeReleaseConfirm,
SNodeCounterCheckRequest,
SNodeChangeRequired,
SNodeChangeConfirm,
SNodeChangeRefuse,
RRCTransfer,
XnRemovalRequest,
XnRemovalResponse,
XnRemovalFailure,
XnSetupRequest,
XnSetupResponse,
XnSetupFailure,
NGRANNodeConfigurationUpdate,
NGRANNodeConfigurationUpdateAcknowledge,
NGRANNodeConfigurationUpdateFailure,
E-UTRA-NR-CellResourceCoordinationRequest,
E-UTRA-NR-CellResourceCoordinationResponse,
ActivityNotification,
CellActivationRequest,
CellActivationResponse,
CellActivationFailure,
ResetRequest,
ResetResponse,
ErrorIndication,
PrivateMessage,
DeactivateTrace,
TraceStart,
HandoverSuccess,
ConditionalHandoverCancel,
EarlyStatusTransfer,
FailureIndication,
HandoverReport,
SCGFailureIndication,
ResourceStatusRequest,
ResourceStatusResponse,
ResourceStatusFailure,
ResourceStatusUpdate,
MobilityChangeRequest,
MobilityChangeAcknowledge,
MobilityChangeFailure,
AccessAndMobilityIndication,
CellTrafficTrace,
RANMulticastGroupPaging,
ScgFailureInformationReport,
ScgFailureTransfer,
F1CTrafficTransfer,
IABTransportMigrationManagementRequest,
IABTransportMigrationManagementResponse,
IABTransportMigrationManagementReject,
IABTransportMigrationModificationRequest,
IABTransportMigrationModificationResponse,
IABResourceCoordinationRequest,
IABResourceCoordinationResponse,
CPCCancel,
PartialUEContextTransfer,
PartialUEContextTransferAcknowledge,
PartialUEContextTransferFailure,
RachIndication,
DataCollectionRequest,
DataCollectionResponse,
DataCollectionFailure,
DataCollectionUpdate,
ODSIB1ConfigurationProvisionRequest,
ODSIB1ConfigurationProvisionResponse,
ODSIB1ConfigurationProvisionFailure,
ODSIB1ConfigurationProvisionStatus,
LTMConfigurationUpdate,
LTMConfigurationUpdateAcknowledge,
LTMConfigurationUpdateFailure,
CSIRSCoordinationRequest,
CSIRSCoordinationResponse,
CellSwitchNotification,
TAInformationTransfer,
LTMCancel,
CLI-Indication
FROM XnAP-PDU-Contents
id-handoverPreparation,
id-sNStatusTransfer,
id-handoverCancel,
id-notificationControl,
id-retrieveUEContext,
id-rANPaging,
id-xnUAddressIndication,
id-uEContextRelease,
id-secondaryRATDataUsageReport,
id-sNGRANnodeAdditionPreparation,
id-sNGRANnodeReconfigurationCompletion,
id-mNGRANnodeinitiatedSNGRANnodeModificationPreparation,
id-sNGRANnodeinitiatedSNGRANnodeModificationPreparation,
id-mNGRANnodeinitiatedSNGRANnodeRelease,
id-sNGRANnodeinitiatedSNGRANnodeRelease,
id-sNGRANnodeCounterCheck,
id-sNGRANnodeChange,
id-activityNotification,
id-rRCTransfer,
id-xnRemoval,
id-xnSetup,
id-nGRANnodeConfigurationUpdate,
id-e-UTRA-NR-CellResourceCoordination,
id-cellActivation,
id-reset,
id-errorIndication,
id-privateMessage,
id-deactivateTrace,
id-traceStart,
id-handoverSuccess,
id-conditionalHandoverCancel,
id-earlyStatusTransfer,
id-failureIndication,
id-handoverReport,
id-scgFailureIndication,
id-resourceStatusReportingInitiation,
id-resourceStatusReporting,
id-mobilitySettingsChange,
id-accessAndMobilityIndication,
id-cellTrafficTrace,
id-RANMulticastGroupPaging,
id-scgFailureInformationReport,
id-scgFailureTransfer,
id-f1CTrafficTransfer,
id-iABTransportMigrationManagement,
id-iABTransportMigrationModification,
id-iABResourceCoordination,
id-retrieveUEContextConfirm,
id-cPCCancel,
id-partialUEContextTransfer,
id-rachIndication,
id-dataCollectionReportingInitiation,
id-dataCollectionReporting,
id-ODSIB1ConfigurationProvision,
id-ODSIB1ConfigurationProvisionStatus,
id-lTMConfigurationUpdate,
id-cSIRSCoordination,
id-cellSwitchNotification,
id-tAInformationTransfer,
id-lTMCancel,
id-cLI-Indication
FROM XnAP-Constants;
-- **************************************************************
--
-- Interface Elementary Procedure Class
--
-- **************************************************************
XNAP-ELEMENTARY-PROCEDURE ::= CLASS {
&InitiatingMessage ,
&SuccessfulOutcome OPTIONAL,
&UnsuccessfulOutcome OPTIONAL,
&procedureCode ProcedureCode UNIQUE,
&criticality Criticality DEFAULT ignore
}
WITH SYNTAX {
INITIATING MESSAGE &InitiatingMessage
[SUCCESSFUL OUTCOME &SuccessfulOutcome]
[UNSUCCESSFUL OUTCOME &UnsuccessfulOutcome]
PROCEDURE CODE &procedureCode
[CRITICALITY &criticality]
}
-- **************************************************************
--
-- Interface PDU Definition
--
-- **************************************************************
XnAP-PDU ::= CHOICE {
initiatingMessage InitiatingMessage,
successfulOutcome SuccessfulOutcome,
unsuccessfulOutcome UnsuccessfulOutcome,
...
}
InitiatingMessage ::= SEQUENCE {
procedureCode XNAP-ELEMENTARY-PROCEDURE.&procedureCode ({XNAP-ELEMENTARY-PROCEDURES}),
criticality XNAP-ELEMENTARY-PROCEDURE.&criticality ({XNAP-ELEMENTARY-PROCEDURES}{@procedureCode}),
value XNAP-ELEMENTARY-PROCEDURE.&InitiatingMessage ({XNAP-ELEMENTARY-PROCEDURES}{@procedureCode})
}
SuccessfulOutcome ::= SEQUENCE {
procedureCode XNAP-ELEMENTARY-PROCEDURE.&procedureCode ({XNAP-ELEMENTARY-PROCEDURES}),
criticality XNAP-ELEMENTARY-PROCEDURE.&criticality ({XNAP-ELEMENTARY-PROCEDURES}{@procedureCode}),
value XNAP-ELEMENTARY-PROCEDURE.&SuccessfulOutcome ({XNAP-ELEMENTARY-PROCEDURES}{@procedureCode})
}
UnsuccessfulOutcome ::= SEQUENCE {
procedureCode XNAP-ELEMENTARY-PROCEDURE.&procedureCode ({XNAP-ELEMENTARY-PROCEDURES}),
criticality XNAP-ELEMENTARY-PROCEDURE.&criticality ({XNAP-ELEMENTARY-PROCEDURES}{@procedureCode}),
value XNAP-ELEMENTARY-PROCEDURE.&UnsuccessfulOutcome ({XNAP-ELEMENTARY-PROCEDURES}{@procedureCode})
}
-- **************************************************************
--
-- Interface Elementary Procedure List
The gui/ subdirectory contains an ASN.1 Studio project for this sample. With ASN.1 Studio you can:
This sample is provided solely for illustration purposes, for example to demonstrate usage of the OSS ASN.1 Tools API with 3GPP 5G XnAP messages. It does not represent a complete application. To build and run this sample, you must use a trial or licensed version of the appropriate OSS ASN.1 Tools. The copyright and license statements included in each source file remain fully applicable.
If you have questions about using this sample, contact OSS Nokalva Support.