LTE X2AP C# Sample Code Using OSS ASN.1 Tools


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 LTE X2AP standard (TS 36.423 version 19.0.0).

It runs on Windows as an example and illustrates how to decode, inspect, and create LTE X2AP messages using the OSS ASN.1 Tools API.

The sample reads X2AP messages from .per files, decodes and prints them, and creates and encodes successful outcome messages.

A Windows batch script (run.bat) is included for running the test program.

To explore more samples (LTE RRC, 5G RRC, S1AP, X2AP, NGAP), visit the main Sample Code page.

Overview

This sample shows how to:

  • Initialize the OSS ASN.1/C# runtime for the LTE X2AP schema.
  • Read a PER-encoded X2AP message from an input file.
  • Decode and print LTE X2AP messages.
  • Access message components.
  • Create and encode a successful outcome message.
  • Run the sample test program using the provided run.bat script.

Files in This Sample

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.
x2ap.asn ASN.1 source file that describes the 3GPP LTE X2AP protocol (TS 36.423) used with this program example.
x2ap-directives.asn Contains additional directives for x2ap.asn.
X2AP-PDU_HandoverRequest_bin.per Valid PER-encoded X2AP message. It should pass testing.
app.cs Simple C# program that shows how to work with LTE X2AP protocol data. It reads input messages from files, decodes and prints them, and creates and encodes successful outcome messages.
gui/ ASN.1 Studio project for viewing/compiling schema and generating sample data.
run.bat Windows batch script that runs the sample test.

Build and Run Instructions

(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#.

1. Verify environment variables (if not using the OSS command prompt)

If you use the OSS command prompt window, you do not need to set environment variables to run this sample. Otherwise, ensure the following are defined:

  • OSS_CSHARP_HOME
  • PATH (must include the OSS bin directory)

If using Visual Studio, run the Microsoft vsvars32.bat script to set up the .NET command-line environment. If Visual Studio is not installed, ensure your PATH includes the required .NET directories. For details, see ossvars.bat installed with the product.

2. Run the sample
run
3. Clean up generated files
run clean
4. Other Platforms

Note: The C# source code in this sample is platform-independent. Windows commands are shown as an example, but equivalent samples and run instructions may be available for other platforms. For help with platform-specific instructions, please contact OSS Support.

Code Listing: app.cs

The following listing shows the main C# source file for this sample test program, app.cs. It demonstrates how to read PER-encoded LTE X2AP messages from files, decode and print them, and create and encode a response message using the OSS ASN.1 Tools API.

Show app.cs source code
///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2025 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 part of the LTE X2AP protocol.
//


// Classes generated from ASN.1 specification.
using X2ap;
using X2ap.X2APPDUDescriptions;
using X2ap.X2APPDUContents;
using X2ap.X2APContainers;
using X2ap.X2APIEs;

// Classes from the OSS runtime library.
using Oss.Asn1;

// C# system classes.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;


public class Program
{
    public static int Main(string[] args)
    {
	try
	{
	    // A folder with encoded messages.
	    string dataDir = (args.Length > 0) ? args[0] : "../../";
	    Tx2ap tx2ap = new Tx2ap();
	    tx2ap.Process(dataDir, "X2AP-PDU_HandoverRequest_bin.per");
	    Console.WriteLine("Message processing has completed successfully.");
	    return 0;
	}
	catch (Exception e)
	{
	    // Print complete exception information.
	    Console.WriteLine("ERROR: Error processing input files.");
	    Console.WriteLine(e);
	    return 1;
	}
    }
}

/// <summary>
/// Does all the processing of the files with encoded PDUs.
/// </summary>
public class Tx2ap
{
    PerAlignedCodec codec = new PerAlignedCodec();
    /// <summary>
    /// Processes a file with encoded X2AP PDU.
    /// </summary>
    public void Process(String dataDir, String fileName)
    {
	try
	{
	    String fullPath = Path.Combine(dataDir, fileName);
	    X2APPDU req = DecodeRequest(fullPath);
	    Console.WriteLine("\nPrinting the PER-Decoded X2APPDU PDU...\n");
	    ValueNotationFormatter.Print(req, Console.Out);
	    X2APPDU res = CreateResponse(req);
	    if (res != null) {
		Console.WriteLine("\nPrinting the created X2APPDU response PDU...\n");
		ValueNotationFormatter.Print(res, Console.Out);
		EncodeAndSend(res);
	    }
	    Console.WriteLine();
	}
	catch (Exception e)
	{
	    throw new Exception("Unable to process file '" + fileName + "'.", e);
	}
    }

    /// <summary>
    /// Creates an X2APPDU InitiatingMessage.
    /// </summary>
    X2APPDU CreateResponse(X2APPDU request)
    {
	// Check that the message contains InitiatingMessage
	if (request.Selected != X2APPDU.Id.InitiatingMessageChosen)
	    throw new Exception("ERROR: Wrong message.  Expecting InitiatingMessage.");

	InitiatingMessage msg = request.InitiatingMessage;
	ProcedureCode code = ProcedureCodes.ContainsKey(msg.ProcedureCode) ? ProcedureCodes[msg.ProcedureCode] : ProcedureCode.Unknown;

	switch (code) {
	    case ProcedureCode.HandoverRequest: {
		    HandoverRequest req = (HandoverRequest)msg.Value.Decoded;
		    AccessHandoverRequestIEs(req);
		    return CreateHandoverRequestAcknowledge(req);
		}
	    case ProcedureCode.Unknown:
		Console.WriteLine("WARNING: Got unknown ProcedureCode: " + msg.ProcedureCode);
		return null;
	    default:
		Console.WriteLine("WARNING: ProcedureCode " + code + " not implemented yet.");
		return null;
	}
    }

    /// <summary>
    /// Creates a HandoverRequestAcknowledge PDU.
    /// </summary>
    public X2APPDU CreateHandoverRequestAcknowledge(HandoverRequest req)
    {
	Console.WriteLine("\nCreating a HandoverRequestAcknowledge X2APPDU PDU message...");
	HandoverRequest.ProtocolIEsType request_IEs = req.ProtocolIEs;

	if (request_IEs == null || request_IEs.Count == 0) {
	    Console.WriteLine("No IEs in the HandoverRequest message.");
	    return null;
	}
	UEX2APID srcv_assoc_ID = null;
	foreach (HandoverRequest.ProtocolIEsType.Element ie in request_IEs)
	    if (ie.Id == X2ap.X2APConstants.Values.IdOldENBUEX2APID)
		srcv_assoc_ID = (UEX2APID)ie.Value.Decoded;
	if (srcv_assoc_ID == null) {
	    Console.WriteLine("Invalid HandoverRequest.");
	    return null;
	}
	HandoverRequestAcknowledge.ProtocolIEsType response_IEs = new HandoverRequestAcknowledge.ProtocolIEsType() {
	    new HandoverRequestAcknowledge.ProtocolIEsType.Element() {
		Id = X2ap.X2APConstants.Values.IdOldENBUEX2APID,
		Criticality = X2ap.X2APCommonDataTypes.Criticality.Ignore,
		Value = new OpenType(srcv_assoc_ID)
	    },
	    new HandoverRequestAcknowledge.ProtocolIEsType.Element() {
		Id = X2ap.X2APConstants.Values.IdOldENBUEX2APID,
		Criticality = X2ap.X2APCommonDataTypes.Criticality.Ignore,
		Value = new OpenType(
		    new UEX2APID() {
			Value = 1937
		    }
		)
	    }
	};
	HandoverRequestAcknowledge res = new HandoverRequestAcknowledge() {
	    ProtocolIEs = response_IEs
	};
	SuccessfulOutcome successfulOutcome = new SuccessfulOutcome() {
	    ProcedureCode = X2ap.X2APConstants.Values.IdHandoverPreparation,
	    Criticality = X2ap.X2APCommonDataTypes.Criticality.Reject,
	    Value = new OpenType(res)
	};
	X2APPDU pdu = new X2APPDU();
	pdu.SuccessfulOutcome = successfulOutcome;
	Console.WriteLine("Created the X2APPDU response PDU successfully.\n");
	return pdu;
    }

    /// <summary>
    /// Decodes an X2APPDU PDU from a file.
    /// </summary>
    X2APPDU DecodeRequest(String fileName)
    {
	using (Stream stream = File.OpenRead(fileName))
	{
	    /// <summary>
	    ///  Set the decoder to autodecode open type values.
	    /// </summary>
	    codec.DecoderOptions.AutoDecode = true;
	    Console.WriteLine("\nDecoding the X2APPDU request PDU from the file " + fileName + "...");
	    X2APPDU msg = new X2APPDU();
	    codec.Decode(stream, msg);
	    Console.WriteLine("PDU decoded successfully.");
	    return msg;
	}
    }

    /// <summary>
    /// Enumerates possible procedure codes.
    /// </summary>
    public enum ProcedureCode {
	HandoverRequest,
	Unknown
    }

    static Dictionary<int, ProcedureCode> ProcedureCodes = new Dictionary<int, ProcedureCode>() {
	{X2ap.X2APConstants.Values.IdHandoverPreparation, ProcedureCode.HandoverRequest}
    };

    /// <summary>
    /// Demonstrates how components of HandoverRequest can
    /// be accessed in the code.
    /// </summary>
    /// <param name="req">The HandoverRequest message</param>
    public void AccessHandoverRequestIEs(HandoverRequest req)
    {
	Console.WriteLine("\nAccessing IEs of the HandoverRequest message...\n");
	int ordinal = 0, number = 0;
	foreach (HandoverRequest.ProtocolIEsType.Element ie in req.ProtocolIEs) {
	    ++ordinal;
	    Console.WriteLine("IE #{0}:\nid {1}\ncriticality {2}", ordinal, ie.Id, ie.Criticality);
	    if (ie.Id == X2ap.X2APConstants.Values.IdOldENBUEX2APID) {
		UEX2APID v = (UEX2APID)ie.Value.Decoded;
		Console.WriteLine("value UE-X2AP-ID : {0}\n", v.Value);
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdCause) {
		Cause v = (Cause)ie.Value.Decoded;
		Console.WriteLine("value Cause : {0}\n", v);
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdTargetCellID) {
		ECGI v = (ECGI)ie.Value.Decoded;
		Console.WriteLine("value ECGI :");
		Console.WriteLine("    pLMN-Identity        : {0}", BitConverter.ToString(v.PLMNIdentity));
		Console.WriteLine("    eUTRANcellIdentifier : {0}\n", BitsToString(v.EUTRANcellIdentifier));
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdGUMMEIID) {
		GUMMEI v = (GUMMEI)ie.Value.Decoded;
		Console.WriteLine("value GUMMEI :");
		Console.WriteLine("    gU-Group-ID :");
		Console.WriteLine("        pLMN-Identity : {0}", BitConverter.ToString(v.GUGroupID.PLMNIdentity));
		Console.WriteLine("        mME-Group-ID  : {0}", BitConverter.ToString(v.GUGroupID.MMEGroupID));
		Console.WriteLine("    mME-Code   : {0}\n", BitConverter.ToString(v.MMECode));
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdUEContextInformation) {
		UEContextInformation v = (UEContextInformation)ie.Value.Decoded;
		Console.WriteLine("value UE-ContextInformation:");
		Console.WriteLine("    mME-UE-S1AP-ID : {0}", v.MMEUES1APID);
		Console.WriteLine("    uESecurityCapabilities : ");
		Console.WriteLine("        encryptionAlgorithms : {0}", BitsToString(v.UESecurityCapabilities.EncryptionAlgorithms));
		Console.WriteLine("        encryptionAlgorithms : {0}", BitsToString(v.UESecurityCapabilities.IntegrityProtectionAlgorithms));
		Console.WriteLine("    aS-SecurityInformation : ");
		Console.WriteLine("        key-eNodeB-star      : {0}", BitsToString(v.ASSecurityInformation.KeyENodeBStar));
		Console.WriteLine("        nextHopChainingCount : {0}", v.ASSecurityInformation.NextHopChainingCount);
		Console.WriteLine("    uEaggregateMaximumBitRate : ");
		Console.WriteLine("        uEaggregateMaximumBitRateDownlink : {0}",   v.UEaggregateMaximumBitRate.UEaggregateMaximumBitRateDownlink);
		Console.WriteLine("        uEaggregateMaximumBitRateUplink   : {0}", v.UEaggregateMaximumBitRate.UEaggregateMaximumBitRateUplink);
		Console.WriteLine("    subscriberProfileIDforRFP : {0}", v.SubscriberProfileIDforRFP);
		Console.WriteLine("    e-RABs-ToBeSetup-List :");
		ERABsToBeSetupList vv = v.ERABsToBeSetupList;
		foreach (ERABsToBeSetupList.Element item in vv) {
		    ++number;
		    Console.WriteLine("        IE #{0}:\n        id {1}\n        criticality {2}", number, item.Id, item.Criticality);
		    ERABsToBeSetupItem it = (ERABsToBeSetupItem)item.Value.Decoded;
		    Console.WriteLine("        value E-RABs-ToBeSetup-Item :");
		    Console.WriteLine("            e-RAB-ID : {0}", it.ERABID);
		    Console.WriteLine("            e-RAB-Level-QoS-Parameters :");
		    Console.WriteLine("                qCI : {0}", it.ERABLevelQoSParameters.QCI);
		    Console.WriteLine("                allocationAndRetentionPriority :");
		    Console.WriteLine("                    priorityLevel            : {0}", it.ERABLevelQoSParameters.AllocationAndRetentionPriority.PriorityLevel);
		    Console.WriteLine("                    pre-emptionCapability    : {0}", it.ERABLevelQoSParameters.AllocationAndRetentionPriority.PreEmptionCapability);
		    Console.WriteLine("                    pre-emptionVulnerability : {0}", it.ERABLevelQoSParameters.AllocationAndRetentionPriority.PreEmptionVulnerability);
		    Console.WriteLine("                gbrQosInformation :");
		    Console.WriteLine("                    e-RAB-MaximumBitrateDL    : {0}", it.ERABLevelQoSParameters.GbrQosInformation.ERABMaximumBitrateDL);
		    Console.WriteLine("                    e-RAB-MaximumBitrateUL    : {0}", it.ERABLevelQoSParameters.GbrQosInformation.ERABMaximumBitrateUL);
		    Console.WriteLine("                    e-RAB-GuaranteedBitrateDL : {0}", it.ERABLevelQoSParameters.GbrQosInformation.ERABGuaranteedBitrateDL);
		    Console.WriteLine("                    e-RAB-GuaranteedBitrateDL : {0}", it.ERABLevelQoSParameters.GbrQosInformation.ERABGuaranteedBitrateUL);
		    Console.WriteLine("            dL-Forwarding :", it.DLForwarding);
		    Console.WriteLine("            uL-GTPtunnelEndpoint :");
		    Console.WriteLine("                transportLayerAddress : {0}", BitsToString(it.ULGTPtunnelEndpoint.TransportLayerAddress));
		    Console.WriteLine("                gTP-TEID              : {0}", BitConverter.ToString(it.ULGTPtunnelEndpoint.GTPTEID));
		}
		Console.WriteLine("    rRC-Context : {0}", BitConverter.ToString(v.RRCContext));
		Console.WriteLine("    handoverRestrictionList :");
		Console.WriteLine("        servingPLMN : {0}", BitConverter.ToString(v.HandoverRestrictionList.ServingPLMN));
		Console.WriteLine("        equivalentPLMNs :");
		Console.WriteLine("            servingPLMN : {0}", BitConverter.ToString(v.HandoverRestrictionList.EquivalentPLMNs[0]));
		Console.WriteLine("        forbiddenTAs :");
		Console.WriteLine("            pLMN-Identity : {0}", BitConverter.ToString(v.HandoverRestrictionList.ForbiddenTAs[0].PLMNIdentity));
		Console.WriteLine("            forbiddenTACs : {0}", BitConverter.ToString(v.HandoverRestrictionList.ForbiddenTAs[0].ForbiddenTACs[0]));
		Console.WriteLine("        forbiddenLAs :");
		Console.WriteLine("            pLMN-Identity : {0}", BitConverter.ToString(v.HandoverRestrictionList.ForbiddenLAs[0].PLMNIdentity));
		Console.WriteLine("            forbiddenLACs : {0}", BitConverter.ToString(v.HandoverRestrictionList.ForbiddenLAs[0].ForbiddenLACs[0]));
		Console.WriteLine("        forbiddenInterRATs : {0}", v.HandoverRestrictionList.ForbiddenInterRATs);
		Console.WriteLine("    locationReportingInformation :");
		Console.WriteLine("        eventType  : {0}", v.LocationReportingInformation.EventType);
		Console.WriteLine("        reportArea : {0}",  v.LocationReportingInformation.ReportArea);
		number = 0;
		Console.WriteLine("    iE-Extensions :");
		foreach (UEContextInformation.IEExtensionsType.Element ext in v.IEExtensions) {
		    ++number;
		    Console.WriteLine("        IE #{0}:\n        id {1}\n        criticality {2}", number, ext.Id, ext.Criticality);
		    if (ext.Id == X2ap.X2APConstants.Values.IdManagementBasedMDTallowed)
			Console.WriteLine("        extensionValue ManagementBasedMDTallowed : {0}",  ext.ExtensionValue.Decoded);
		    else if (ext.Id == X2ap.X2APConstants.Values.IdManagementBasedMDTPLMNList) {
			Console.WriteLine("        extensionValue MDTPLMNList : ");
			Console.WriteLine("            {0}", BitConverter.ToString(((MDTPLMNListPdu)ext.ExtensionValue.Decoded).Value[0]));
			Console.WriteLine("            {0}", BitConverter.ToString(((MDTPLMNListPdu)ext.ExtensionValue.Decoded).Value[1]));
		    }
		}
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdUEHistoryInformation) {
		UEHistoryInformationPdu v = (UEHistoryInformationPdu)ie.Value.Decoded;
//		Console.WriteLine("    IE #{0}:\n    id {1}\n    criticality {2}", ordinal, ie.Id, ie.Criticality);
		Console.WriteLine("    value UE-HistoryInformation :");
		Console.WriteLine("        e-UTRAN-Cell :");
		Console.WriteLine("            global-Cell-ID :");
		Console.WriteLine("                pLMN-Identity        : {0}", BitConverter.ToString(v.Value[0].EUTRANCell.GlobalCellID.PLMNIdentity));
		Console.WriteLine("                eUTRANcellIdentifier : {0}", BitsToString(v.Value[0].EUTRANCell.GlobalCellID.EUTRANcellIdentifier));
		Console.WriteLine("            cellType :");
		Console.WriteLine("                cell-Size : {0}", v.Value[0].EUTRANCell.CellType.CellSize);
		Console.WriteLine("            time-UE-StayedInCell : {0}\n", v.Value[0].EUTRANCell.TimeUEStayedInCell);
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdTraceActivation) {
		TraceActivation v = (TraceActivation)ie.Value.Decoded;
		Console.WriteLine("    IE #{0}:\n    id {1}\n    criticality {2}", ordinal, ie.Id, ie.Criticality);
		Console.WriteLine("    value TraceActivation :");
		Console.WriteLine("        eUTRANTraceID                  : {0}", BitConverter.ToString(v.EUTRANTraceID));
		Console.WriteLine("        interfacesToTrace              : {0}", BitsToString(v.InterfacesToTrace));
		Console.WriteLine("        traceDepth                     : {0}", v.TraceDepth);
		Console.WriteLine("        traceCollectionEntityIPAddress : {0}", BitsToString(v.TraceCollectionEntityIPAddress));
		number = 0;
		foreach (TraceActivation.IEExtensionsType.Element ext in v.IEExtensions) {
		    ++number;
		    MDTConfiguration vv = (MDTConfiguration)ext.ExtensionValue.Decoded;
		    Console.WriteLine("    iE-Extensions :");
		    Console.WriteLine("        IE #{0}:\n        id {1}\n        criticality {2}", number, ext.Id, ext.Criticality);
		    Console.WriteLine("        extensionValue MDT-Configuration :");
		    Console.WriteLine("            mdt-Activation : {0}",  vv.MdtActivation);
		    Console.WriteLine("            areaScopeOfMDT tABased :");
		    Console.WriteLine("                tAListforMDT : {0}", BitConverter.ToString(vv.AreaScopeOfMDT.TABased.TAListforMDT[0]));
		    Console.WriteLine("            measurementsToActivate : ", BitsToString(vv.MeasurementsToActivate));
		    Console.WriteLine("            m1reportingTrigger     : ", vv.M1reportingTrigger);
		    Console.WriteLine("            m1periodicReporting    : ");
		    Console.WriteLine("                reportInterval : {0}", vv.M1periodicReporting.ReportInterval);
		    Console.WriteLine("                reportAmount   : {0}\n", vv.M1periodicReporting.ReportAmount);
		}
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdSRVCCOperationPossible) {
		SRVCCOperationPossible v = (SRVCCOperationPossible)ie.Value.Decoded;
		Console.WriteLine("    value SRVCCOperationPossible : {0}\n", v.Value);
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdCSGMembershipStatus) {
		CSGMembershipStatus v = (CSGMembershipStatus)ie.Value.Decoded;
		Console.WriteLine("    value CSGMembershipStatus : {0}\n", v.Value);
	    }
	    else if (ie.Id == X2ap.X2APConstants.Values.IdMobilityInformation) {
		MobilityInformation v = (MobilityInformation)ie.Value.Decoded;
		Console.WriteLine("    value MobilityInformation : {0}\n", v.Value);
	    }
	    else {
		if (ie.Value.Decoded != null)
		    Console.WriteLine(ie.Value.Decoded);
		else
		    Console.WriteLine("IE left undecoded: {0}\n", BitConverter.ToString(ie.Value.Encoded));
	    }
	}
    }

    /// <summary>
    /// A utility method to print bits of a BIT STRING.
    /// </summary>
    /// <param name="bitString">A value of BIT STRING</param>
    /// <returns></returns>
    private string BitsToString(BitString bitString)
    {
	StringBuilder sb = new StringBuilder(bitString.Length);
	foreach (bool bit in bitString)
	    sb.Append(bit ? "1" : "0");
	return sb.ToString();
    }

    /// <summary>
    /// Encode and send message
    /// </summary>
    void EncodeAndSend(X2APPDU message)
    {
	try {
	    using (MemoryStream stream = new MemoryStream()) {
		Console.WriteLine("Encoding the X2APPDU response PDU using memory stream...");
		codec.Encode(message, stream);
		Console.WriteLine("Encoded successfully.\n");
		Console.WriteLine("Printing the X2APPDU response PDU in " + stream.Length + " bytes...");
		Console.WriteLine(BitConverter.ToString(stream.ToArray()));
	    }
	    Console.WriteLine("\nEncoding the X2APPDU response PDU again using a class object...");
	    byte[] encoded = codec.Encode(message);
	    Console.WriteLine("Encoded successfully.\n");
	    Console.WriteLine("Printing the X2APPDU response PDU in " + encoded.Length + " bytes...");
	    ValueNotationFormatter.Print(encoded, encoded.Length, Console.Out);
	} catch (Exception e) {
	    throw new Exception("ERROR: Failed to encode.", e);
	}
    }
}

Expected Output (Excerpt)

This is the expected output when running the sample:

Encoding response message...
Encoding successful.

ASN.1 Schema Excerpt (x2ap.asn)

Show excerpt from x2ap.asn
-- Excerpt from x2ap.asn 3GPP TS 36.423 V19.0.0 (2025-09) 

-- Elementary Procedure definitions
--
-- **************************************************************

X2AP-PDU-Descriptions {
itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) 
eps-Access (21) modules (3) x2ap (2) version1 (1) x2ap-PDU-Descriptions (0) }

DEFINITIONS AUTOMATIC TAGS ::= 

BEGIN

-- **************************************************************
--
-- IE parameter types from other modules.
--
-- **************************************************************

IMPORTS
	Criticality,
	ProcedureCode

FROM X2AP-CommonDataTypes

	CellActivationRequest,
	CellActivationResponse,
	CellActivationFailure,
	ENBConfigurationUpdate,
	ENBConfigurationUpdateAcknowledge,
	ENBConfigurationUpdateFailure,
	ErrorIndication,
	HandoverCancel,
	HandoverReport,
	HandoverPreparationFailure,
	HandoverRequest,
	HandoverRequestAcknowledge,
	LoadInformation,
	PrivateMessage,
	ResetRequest,
	ResetResponse,
	ResourceStatusFailure,
	ResourceStatusRequest,
	ResourceStatusResponse,
	ResourceStatusUpdate, 
	RLFIndication,
	SNStatusTransfer,
	UEContextRelease,
	X2SetupFailure,
	X2SetupRequest,
	X2SetupResponse,
	MobilityChangeRequest,
	MobilityChangeAcknowledge,
	MobilityChangeFailure,
	X2Release,
	X2APMessageTransfer,
	SeNBAdditionRequest,
	SeNBAdditionRequestAcknowledge,
	SeNBAdditionRequestReject,
	SeNBReconfigurationComplete,
	SeNBModificationRequest,
	SeNBModificationRequestAcknowledge,
	SeNBModificationRequestReject,
	SeNBModificationRequired,
	SeNBModificationConfirm,
	SeNBModificationRefuse,
	SeNBReleaseRequest,
	SeNBReleaseRequired,
	SeNBReleaseConfirm,
	SeNBCounterCheckRequest,
	X2RemovalFailure,
	X2RemovalRequest,
	X2RemovalResponse,
	RetrieveUEContextRequest,
	RetrieveUEContextResponse,
	RetrieveUEContextFailure,
	SgNBAdditionRequest,
	SgNBAdditionRequestAcknowledge,
	SgNBAdditionRequestReject,
	SgNBReconfigurationComplete,
	SgNBModificationRequest,
	SgNBModificationRequestAcknowledge,
	SgNBModificationRequestReject,
	SgNBModificationRequired,
	SgNBModificationConfirm,
	SgNBModificationRefuse,
	SgNBReleaseRequest,
	SgNBReleaseRequestAcknowledge,
	SgNBReleaseRequestReject,
	SgNBReleaseRequired,
	SgNBReleaseConfirm,
	SgNBCounterCheckRequest,
	SgNBChangeRequired,
	SgNBChangeConfirm,
	SgNBChangeRefuse,
	RRCTransfer,
	ENDCX2SetupRequest,
	ENDCX2SetupResponse,
	ENDCX2SetupFailure,
	ENDCConfigurationUpdate,
	ENDCConfigurationUpdateAcknowledge,
	ENDCConfigurationUpdateFailure,
	SecondaryRATDataUsageReport,
	ENDCCellActivationRequest,
	ENDCCellActivationResponse,
	ENDCCellActivationFailure,
	ENDCPartialResetRequired,
	ENDCPartialResetConfirm,
	EUTRANRCellResourceCoordinationRequest,
	EUTRANRCellResourceCoordinationResponse,
	SgNBActivityNotification,
	ENDCX2RemovalRequest,
	ENDCX2RemovalResponse,
	ENDCX2RemovalFailure,
	DataForwardingAddressIndication,
	GNBStatusIndication,
	ENDCConfigurationTransfer,
	DeactivateTrace,
	TraceStart,
	HandoverSuccess,
	EarlyStatusTransfer,
	ConditionalHandoverCancel,
	ENDCResourceStatusRequest,
	ENDCResourceStatusResponse,
	ENDCResourceStatusFailure,
	ENDCResourceStatusUpdate,
	CellTrafficTrace,
	F1CTrafficTransfer,
	UERadioCapabilityIDMappingRequest,
	UERadioCapabilityIDMappingResponse,
	AccessAndMobilityIndication,
	CPC-cancel,
	RachIndication,
	SCGFailureInformationReport,
	SCGFailureTransfer





FROM X2AP-PDU-Contents

	id-cellActivation,
	id-eNBConfigurationUpdate,
	id-errorIndication,
	id-handoverCancel, 
	id-handoverReport,
	id-handoverPreparation,
	
	id-loadIndication,
	id-privateMessage,
	id-reset,
	
	id-resourceStatusReporting,
	id-resourceStatusReportingInitiation, 
	id-rLFIndication,
	id-snStatusTransfer,
	id-uEContextRelease,
	id-x2Setup,
	id-mobilitySettingsChange,
	id-x2Release,
	id-x2APMessageTransfer,
	id-seNBAdditionPreparation,
	id-seNBReconfigurationCompletion,
	id-meNBinitiatedSeNBModificationPreparation,
	id-seNBinitiatedSeNBModification,
	id-meNBinitiatedSeNBRelease,
	id-seNBinitiatedSeNBRelease,
	id-seNBCounterCheck,
	id-x2Removal,
	id-retrieveUEContext,
	id-sgNBAdditionPreparation,
	id-sgNBReconfigurationCompletion,
	id-meNBinitiatedSgNBModificationPreparation,
	id-sgNBinitiatedSgNBModification,
	id-meNBinitiatedSgNBRelease,
	id-sgNBinitiatedSgNBRelease,
	id-sgNBChange,
	id-sgNBCounterCheck,
	id-rRCTransfer,
	id-endcX2Setup,
	id-endcConfigurationUpdate,
	id-secondaryRATDataUsageReport,
	id-endcCellActivation,
	id-endcPartialReset,
	id-eUTRANRCellResourceCoordination,
	id-SgNBActivityNotification,
	id-endcX2Removal,
	id-dataForwardingAddressIndication,
	id-gNBStatusIndication,
	id-endcConfigurationTransfer,
	id-deactivateTrace,
	id-traceStart,
	id-handoverSuccess,
	id-earlyStatusTransfer,
	id-conditionalHandoverCancel,
	id-endcresourceStatusReporting,
	id-endcresourceStatusReportingInitiation,
	id-cellTrafficTrace,
	id-f1CTrafficTransfer,
	id-UERadioCapabilityIDMapping,
	id-accessAndMobilityIndication,
	id-CPC-cancel,
	id-rachIndication,
	id-scgFailureInformationReport,
	id-scgFailureTransfer




FROM X2AP-Constants;

-- **************************************************************
--
-- Interface Elementary Procedure Class
--
-- **************************************************************

X2AP-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]
}

Using ASN.1 Studio (Optional)

The gui/ subdirectory contains an ASN.1 Studio project for this sample. With ASN.1 Studio you can:

  • Open the LTE X2AP ASN.1 modules.
  • Generate code from the ASN.1 schema.
  • Create and edit sample encoded LTE X2AP messages.
  • Export each project to a Visual Studio project.

Related Samples

Disclaimer

This sample is provided solely for illustration purposes, for example to demonstrate usage of the OSS ASN.1 Tools API with 3GPP LTE X2AP 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.

Need Help?

If you have questions about using this sample, contact OSS Nokalva Support.

See Also