5G RRC 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 5G RRC standard (TS 38.331 version 19.0.0).

It runs on Windows as an example and illustrates how to decode, inspect, and create PER Unaligned 5G RRC messages using the OSS ASN.1 Tools API.

The sample reads RRC messages from .uper files, decodes and prints them, accesses message components, and creates and encodes a response message.

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 5G RRC schema.
  • Read .uper files that contain valid PER-encoded 5G RRC messages.
  • Decode and print 5G RRC messages.
  • Access RRC message components.
  • Create and encode a response message (for example, for SecurityModeCommand).
  • 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.
rrc.asn ASN.1 source file that describes the 3GPP 5G RRC protocol (TS 38.331), used with this program example.
RRCRelease.uper Valid RRCRelease message encoded with PER Unaligned.
SecurityModeCommand.uper Valid SecurityModeCommand message encoded with PER Unaligned.
app.cs Simple C# program that shows how to work with 5G RRC protocol data. It reads input messages from files, decodes and prints them, accesses message components, and creates and encodes a response message for SecurityModeCommand.
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 5G RRC 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.                                            //
///////////////////////////////////////////////////////////////////////////////
// $Id: 5G-rrc-csharp.html 3327 2026-01-06 10:07:48Z macra $

//
// Demonstrates part of the RRC protocol layer of a 5G UE stack.
//

// Classes generated from the ASN.1 specification.
using Rrc;
using Rrc.NRRRCDefinitions;

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

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


public class Program
{
    public static int Main(string[] args)
    {
        try
        {
            // A folder that contains encoded messages.
            string dataDir = (args.Length > 0) ? args[0] : "../../";
            Trrc trrc = new Trrc();
            trrc.Process(dataDir, "RRCRelease.uper");
            trrc.Process(dataDir, "SecurityModeCommand.uper");
            Console.WriteLine("Message processing has completed successfully.");
        }
        catch (Exception e)
        {
            // Print complete exception information.
            Console.WriteLine(e);
            return 1;
        }
        return 0;
    }
}

/// <summary>
/// This represents an incomplete implementation of a UE-side function that processes a downlink DCCH message.
/// It decodes the message, prints it, and creates a response for some particular alternatives.
/// The class can be used to implement a complete 5G RRC UE-side dispatcher.
/// </summary>
public class Trrc
{
    PerUnalignedCodec codec = new PerUnalignedCodec();

    /// <summary>
    /// Processes an input file.
    /// Decodes and prints the input messages.
    /// Creates, encodes, and prints the output (response) messages.
    /// </summary>
    public void Process(String dataDir, String fileName)
    {
        try
        {
            String fullPath = Path.Combine(dataDir, fileName);
            DLDCCHMessage request = GetRequest(fullPath);
            ULDCCHMessage response = GetResponse(request);
            if (response != null)
            	Send(response);
            Console.WriteLine();
        }
        catch (Exception e)
        {
            throw new Exception("Processing error for file: " + fileName, e);
        }
    }

    /// <summary>
    /// This methods decodes a DLDCCHMessage PDU from a file.
    /// </summary>
    DLDCCHMessage GetRequest(String fileName)
    {
        using (Stream stream = File.OpenRead(fileName))
        {
            Console.WriteLine("Decoding the DLDCCHMessage PDU from the file " + fileName + "...");
            DLDCCHMessage request = new DLDCCHMessage();
            codec.Decode(stream, request);
            Console.WriteLine("PDU decoded successfully.");
            return request;
        }
    }

    /// <summary>
    /// This method creates a UL_DCCH_Message PDU for a given DL_DCCH_Message PDU
    /// </summary>
    ULDCCHMessage GetResponse(DLDCCHMessage request)
    {
        // Checking message.
        // The selected CHOICE alternative can be found by comparing the fields with null.
        if (request.Message.C1 == null)
            throw new Exception("Invalid message.");
        // The selected CHOICE alternative can be found
        // by comparing the Selected field with the corresponding enum items.
        switch (request.Message.C1.Selected) {
            // You can add support for each unimplemented CHOICE alternative.
            case DLDCCHMessageType.C1Type.Id.CounterCheckChosen :
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.DlDedicatedMessageSegmentR16Chosen:
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.DlInformationTransferChosen:
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.DlInformationTransferMRDCR16Chosen:
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.LoggedMeasurementConfigurationR16Chosen:
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.MobilityFromNRCommandChosen:
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.RrcReconfigurationChosen :
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.RrcReestablishmentChosen :
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.RrcReleaseChosen :
                Console.WriteLine("Printing the decoded request RRCRelease...");
                ValueNotationFormatter.Print(request, Console.Out);
                return null;
            case DLDCCHMessageType.C1Type.Id.RrcResumeChosen :
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.SecurityModeCommandChosen:
                Console.WriteLine("Printing the decoded request SecurityModeCommand...");
                ValueNotationFormatter.Print(request, Console.Out);
                return CreateSecurityModeCommandResponse(request);
            case DLDCCHMessageType.C1Type.Id.Spare1Chosen:
            case DLDCCHMessageType.C1Type.Id.Spare2Chosen:
            case DLDCCHMessageType.C1Type.Id.Spare3Chosen:
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.UeCapabilityEnquiryChosen :
                Console.WriteLine("Unimplemented.");
                return null;
            case DLDCCHMessageType.C1Type.Id.UeInformationRequestR16Chosen:
                Console.WriteLine("Unimplemented.");
                return null;
            default:
                Console.WriteLine("Unknown CHOICE alternative selected.");
                return null;
        }
    }

    /// <summary>
    /// This method creates a "security mode complete" ULDCCHMessage PDU
    /// for the given "security mode command" DL_DCCH_Message PDU.
    /// </summary>
    ULDCCHMessage CreateSecurityModeCommandResponse(DLDCCHMessage request)
    {
        Console.WriteLine("\nCreating the ULDCCHMessage response message...");
        // Check if request is valid.
        if (request.Message.C1 == null ||
            request.Message.C1.SecurityModeCommand == null ||
            request.Message.C1.SecurityModeCommand.CriticalExtensions.SecurityModeCommand == null)
                throw new Exception("Cannot handle ASN.1 data");
        SecurityAlgorithmConfig config = request.Message.C1.
                         SecurityModeCommand.CriticalExtensions.
                         SecurityModeCommand.SecurityConfigSMC.SecurityAlgorithmConfig;
        switch (config.IntegrityProtAlgorithm) {
            case IntegrityProtAlgorithm.Nia0:
            case IntegrityProtAlgorithm.Nia1:
            case IntegrityProtAlgorithm.Nia2:
            case IntegrityProtAlgorithm.Nia3:
                break;
            default:
                throw new Exception("Unknown integrity protection");
        }
        switch (config.CipheringAlgorithm) {
            case CipheringAlgorithm.Nea0:
            case CipheringAlgorithm.Nea1:
            case CipheringAlgorithm.Nea2:
            case CipheringAlgorithm.Nea3:
                break;
            default:
                throw new Exception("Unknown ciphering");
        }
        SecurityModeComplete securityModeComplete = new SecurityModeComplete();
        securityModeComplete.CriticalExtensions = new SecurityModeComplete.CriticalExtensionsType();
        securityModeComplete.CriticalExtensions.SecurityModeComplete = new SecurityModeCompleteIEs();
        securityModeComplete.RrcTransactionIdentifier = request.Message.C1.SecurityModeCommand.RrcTransactionIdentifier;

        ULDCCHMessage response = new ULDCCHMessage();
        response.Message = new ULDCCHMessageType();
        response.Message.C1 = new ULDCCHMessageType.C1Type();
        response.Message.C1.SecurityModeComplete = securityModeComplete;
        Console.WriteLine("Response created successfully.");
        Console.WriteLine("\nPrinting the created response...");
        ValueNotationFormatter.Print(response, Console.Out);
        return response;
    }

    /// <summary>
    /// Encodes and sends a ULDCCHMessage message.
    /// </summary>
    void Send(ULDCCHMessage message)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            Console.WriteLine("Encoding the response...");
            codec.Encode(message, stream);
            Console.WriteLine("Encoded successfully.\n");
            // Print the encoded outcome message.
            Console.WriteLine("Printing the response PDU in " + stream.Length + " bytes...");
            ValueNotationFormatter.Print(stream.ToArray(), (int)stream.Length, Console.Out);
        }
    }
}

Expected Output (Excerpt)

This is the expected output when running the sample:

Decoded RRCRelease:
  rrc-TransactionId = 1
  criticalExtensions = ...
Encoding response message...
Encoding successful.

ASN.1 Schema Excerpt (rrc.asn)

Show excerpt from rrc.asn
-- Excerpt from rrc.asn 3GPP 38.331 V19.0.0 (2025-09)

-- TAG-NR-RRC-DEFINITIONS-START

NR-RRC-Definitions DEFINITIONS AUTOMATIC TAGS ::=

BEGIN

-- TAG-NR-RRC-DEFINITIONS-STOP

-- TAG-BCCH-BCH-MESSAGE-START

BCCH-BCH-Message ::=            SEQUENCE {
    message                         BCCH-BCH-MessageType
}

BCCH-BCH-MessageType ::=        CHOICE {
    mib                             MIB,
    messageClassExtension           SEQUENCE {}
}

-- TAG-BCCH-BCH-MESSAGE-STOP

-- TAG-BCCH-DL-SCH-MESSAGE-START

BCCH-DL-SCH-Message ::=         SEQUENCE {
    message                         BCCH-DL-SCH-MessageType
}

BCCH-DL-SCH-MessageType ::=     CHOICE {
    c1                              CHOICE {
        systemInformation               SystemInformation,
        systemInformationBlockType1     SIB1
    },
    messageClassExtension           SEQUENCE {}
}

-- TAG-BCCH-DL-SCH-MESSAGE-STOP

-- TAG-DL-CCCH-MESSAGE-START

DL-CCCH-Message ::=             SEQUENCE {
    message                         DL-CCCH-MessageType
}

DL-CCCH-MessageType ::=         CHOICE {
    c1                              CHOICE {
        rrcReject                       RRCReject,
        rrcSetup                        RRCSetup,
        spare2                          NULL,
        spare1                          NULL
    },
    messageClassExtension           SEQUENCE {}
}

-- TAG-DL-CCCH-MESSAGE-STOP

-- TAG-DL-DCCH-MESSAGE-START

DL-DCCH-Message ::=                  SEQUENCE {
    message                             DL-DCCH-MessageType
}

DL-DCCH-MessageType ::=             CHOICE {
    c1                                  CHOICE {
        rrcReconfiguration                  RRCReconfiguration,
        rrcResume                           RRCResume,
        rrcRelease                          RRCRelease,
        rrcReestablishment                  RRCReestablishment,
        securityModeCommand                 SecurityModeCommand,
        dlInformationTransfer               DLInformationTransfer,
        ueCapabilityEnquiry                 UECapabilityEnquiry,
        counterCheck                        CounterCheck,
        mobilityFromNRCommand               MobilityFromNRCommand,
        dlDedicatedMessageSegment-r16       DLDedicatedMessageSegment-r16,
        ueInformationRequest-r16            UEInformationRequest-r16,
        dlInformationTransferMRDC-r16       DLInformationTransferMRDC-r16,
        loggedMeasurementConfiguration-r16  LoggedMeasurementConfiguration-r16,
                spare3 NULL, spare2 NULL, spare1 NULL
    },
    messageClassExtension   SEQUENCE {}
}

-- TAG-DL-DCCH-MESSAGE-STOP

-- TAG-MCCH-MESSAGE-START

MCCH-Message-r17 ::= SEQUENCE {
    message              MCCH-MessageType-r17
}

MCCH-MessageType-r17 ::= CHOICE {
    c1                       CHOICE {
        mbsBroadcastConfiguration-r17     MBSBroadcastConfiguration-r17,
        spare1                            NULL
    },
    messageClassExtension   SEQUENCE {}
}

-- TAG-MCCH-MESSAGE-STOP

-- TAG-MULTICASTMCCH-MESSAGE-START

MulticastMCCH-Message-r18 ::= SEQUENCE {
    message               MulticastMCCH-MessageType-r18
}

MulticastMCCH-MessageType-r18 ::= CHOICE {
    c1                        CHOICE {
        mbsMulticastConfiguration-r18     MBSMulticastConfiguration-r18,
        spare1                            NULL
    },
    messageClassExtension    SEQUENCE {}
}

-- TAG-MULTICASTMCCH-MESSAGE-STOP

-- TAG-PCCH-PCH-MESSAGE-START

PCCH-Message ::=                SEQUENCE {
    message                         PCCH-MessageType
}

PCCH-MessageType ::=            CHOICE {
    c1                              CHOICE {
        paging                          Paging,
        spare1  NULL
    },
    messageClassExtension       SEQUENCE {}
}

-- TAG-PCCH-PCH-MESSAGE-STOP

-- TAG-UL-CCCH-MESSAGE-START


UL-CCCH-Message ::=             SEQUENCE {
    message                         UL-CCCH-MessageType
}

UL-CCCH-MessageType ::=         CHOICE {
    c1                              CHOICE {
        rrcSetupRequest                 RRCSetupRequest,
        rrcResumeRequest                RRCResumeRequest,
        rrcReestablishmentRequest       RRCReestablishmentRequest,
        rrcSystemInfoRequest            RRCSystemInfoRequest
    },
    messageClassExtension           SEQUENCE {}
}

-- TAG-UL-CCCH-MESSAGE-STOP

-- TAG-UL-CCCH1-MESSAGE-START


UL-CCCH1-Message ::=            SEQUENCE {
    message                         UL-CCCH1-MessageType
}

UL-CCCH1-MessageType ::=        CHOICE {
    c1                              CHOICE {
        rrcResumeRequest1               RRCResumeRequest1,
        spare3 NULL,
        spare2 NULL,
        spare1 NULL

    },
    messageClassExtension SEQUENCE {}
}

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 5G RRC ASN.1 modules.
  • Generate code from the ASN.1 schema.
  • Create and edit sample encoded 5G RRC 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 5G RRC 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