TOP

NAS/C Encoder/Decoder for 5G Advanced Topics

Applies to: NAS/C 5G r15.4.0 v7.1.0

Internal Variables and Data Structures

OssBuf

The encoder uses the OssBuf structure to store its output while the decoder reads its input from this structure.

The OssBuf structure has the following header-file definition:

typedef struct {
	long length;
	unsigned char *value;
} OssBuf;

The value field is designed to reference a memory buffer of contiguous octets of encoded data. The length field stores the total count of octets occupied by the encoding referenced by value.

OssNASGlobal

The OssNASGlobal structure is the global environment variable that is passed to almost all of the OSS NAS/C API functions.

You can manually set the following fields in this structure:

mallocp
All memory allocation performed by the OSS NAS/C API functions described above are done via a call to (*mallocp)(). By default, mallocp points to the malloc() function. You can set it to point to your own low-level memory allocator so long as its function prototype is identical to that of malloc().
freep
All memory freeing performed by the OSS NAS/C API functions described above are done via a call to (*freep)(). By default, freep points to the free() function. You can set it to point to your own low-level memory deallocator so long as its function prototype is identical to that of free().
reallocp
All memory reallocation performed by the OSS NAS/C API functions described above are done via a call to (*realloc)(). By default, reallocp points to the function realloc(). You can set it to point to your own low-level memory reallocator so long as its function prototype is identical to that of realloc().
asn1chop
This field is not used by the present version of the OSS NAS API.
ossblock
This field is not used by the present version of the OSS NAS API.
ossprefx
This field is not used by the present version of the OSS NAS API.
asn1out
This pointer is passed to the (*asn1prnt)() function as the first parameter to determine the output stream to which trace and other requested data is to be written. By default, asn1out is set to stdout. You can change it to reference an output file or another type of output stream.
asn1prnt
Is called by the ossNASPrint() and ossNASPrintPDU() functions. By default, asn1prnt points to fprintf(). You can set it to point to your own print function, as long as it has the same interface as fprintf(). You should set asn1out whenever you set asn1prnt. Failing to do so might cause an application crash if the OSS NAS runtime and your application use different versions of the C runtime.
userVar
This field is not used by the present version of the OSS NAS API. Warning: Aside from the fields documented in this section, you should not explicitly modify any other fields in OssNASGlobal. Doing so may produce unpredictable results.

Function Library Files

The OSS NAS/C API functions are located in various library files. Two types of libraries are provided: dynamic and static. The libraries described in this section are for the MS Windows and Linux platforms.

Dynamic link libraries

The OSS NAS/C API functions are located in a dynamic library file (ossNAS.dll for Windows and libossNAS.so for Linux) that is supplemented by one or more version-specific "plug-in" dynamic libraries. A version-specific library supports one specific version of 3GPP NAS. and is named according to that version number. For example, ossCEFEDXNAS5GS1540.dll on Windows and ossCEFEDXNAS5GS1540.so on Linux are named for 5G NAS version 15.4.0.

To use the OSS NAS dynamic libraries on Windows, specify the ossNAS.lib import library on your linker command-line. Your application program will automatically try to load the ossNAS.dll library as needed during runtime. On Linux, just link with the libossNAS.so shared library. The first time your application calls the ossNASinit function with a specific 3GPP NAS version number, the ossNAS.dll or libossNAS.so library will automatically search for and load the plug-in that supports that 3GPP NAS version.

For Windows, make sure the directory that contains the OSS NAS dynamic library file (ossNAS.dll) is included in the operating system's environment path. Otherwise, your application will be unable to load the library at runtime. All plug-ins must also be located in this directory.

For Linux, make sure the directory that contains the OSS NAS shared library files is included the LD_LIBRARY_PATH environment variable. Otherwise, your application will be unable to load the libraries at runtime.

For Windows, the ossNAS.dll and plug-in DLLs are in the bin directory of the product installation. The ossNAS.lib import library is in the lib directory of the product installation. For Linux, all libraries are in the lib directory of the product installation.

Static link libraries

To use the NAS/C API functions, explicitly specify the appropriate static library on your linker command-line, as follows:

For Linux, link your NAS application code to a single libossNAS5GS1540.a static library, which is located in the lib directory of your product installation.

For Windows, link your NAS application code to a single ossNAS5GS1540.lib static library, which is located in the lib directory of your product installation.

Example

The following sample C program illustrates how to use the OSS 5G NAS/C Encoder/Decoder for 3GPP release 15.4.0. Please pay attention to the memory management methods for using NAS/C APIs.

/* Header file containing C structures for the NAS specification */
#include "NAS5GS1540.h"	

/* OSS NAS/C API header file */
#include "ossNAS.h"	

static int CreateOutgoingUEMessage(OssNASGlobal *nasworld, struct Env *env);
enum 
{ 
	bufferSize = 100000
};

static unsigned char encodedDataBuffer[bufferSize];
static unsigned char unencodedDataBuffer[bufferSize];
static unsigned char decodedDataBuffer[bufferSize];
static unsigned char outTextoutTextBuffer[bufferSize];
static int lenEncodedData;

/* Helper macro that facilitates the construction of an unencoded message */
#define align_adr8(a) (unsigned char *)(((size_t)(a) + 7) & ~7)

#define NEW(T) (freeAddrTemp = align_adr8(freeAddr), freeAddr =freeAddrTemp + sizeof(T), (T *)freeAddrTemp)

  /* Helper macro to set ossOctetString to the value of a string literal */
#define SET_OSTRING_BY_LITERAL(s, literal) {(s).value = (freeAddr = align_adr8(freeAddr));\
    memcpy(freeAddr, literal, sizeof(literal)-1); freeAddr += sizeof(literal)-1;\
    (s).length = sizeof(literal)-1;}

struct Env {
    unsigned char   *encodedDataBuffer;
    unsigned char   *unencodedDataBuffer;
    unsigned char   *decodedDataBuffer;
    unsigned char   *outTextoutTextBuffer;
    int             lenEncodedData;
};

int main(int argc, char *argv[])
{
	OssNASGlobal w, *nasworld = &w; /* Stores the state of the OSS NAS API */
    int exitcode;
    struct Env env;

    /* Make sure the buffer addresses passed to the API are properly aligned */
    env.encodedDataBuffer = align_adr8 (encodedDataBuffer);
    env.unencodedDataBuffer = align_adr8 (unencodedDataBuffer);
    env.decodedDataBuffer = align_adr8 (decodedDataBuffer);
    env.outTextoutTextBuffer = align_adr8 (outTextoutTextBuffer);

   /* Initialize the OSS NAS API */
    exitcode = ossNASinit(nasworld, "NAS5GS1540");
    if (exitcode != 0) {
        ossNASPrint(NULL, "ossNASInit error: %d\n", exitcode);
        return 1;
    }

    ossNASSetFlags(nasworld, 0);

	exitcode = CreateOutgoingUEMessage(nasworld, &env);

    ossNASterm(nasworld);
	return exitcode;
}


static int CreateOutgoingUEMessage(OssNASGlobal *nasworld, struct Env *env)
{
	OssBuf encodedData;
	OssBuf outData;
	int pdu_num = OSSNAS_PDUNUM;
	int retcode;
	NAS5GS1540_NASMessage *nasmessage;
	unsigned char *freeAddr, *freeAddrTemp;
	NAS5GS1540_RegistrationRequest *registrationRequest;
	
	/* Set the originator of NAS messages to "UE" */	
	ossNASSetOriginator(nasworld, OSSNAS_ORIG_UE);

	/* Set the encoding/decoding flags (no flags) */	
	ossNASSetFlags(nasworld, 0);

	freeAddr = env->unencodedDataBuffer;
	nasmessage = NEW(NAS5GS1540_NASMessage);

	/* Construct an unencoded NAS message */
	/* This is a plain 5GSMM message of type NAS5GS1540_RegistrationRequest */
	nasmessage = NEW(NAS5GS1540_NASMessage);
    nasmessage->choice = NAS5GS1540_nas5GMMMessage_chosen;
    nasmessage->u.nas5GMMMessage = NEW(NAS5GS1540_NAS5GMMMessage);
    nasmessage->u.nas5GMMMessage->choice = NAS5GS1540_plain_chosen;
    nasmessage->u.nas5GMMMessage->u.plain = NEW(NAS5GS1540_Plain5GSNASMessage);
    nasmessage->u.nas5GMMMessage->u.plain->extendedProtocolDiscriminator = 126;
    nasmessage->u.nas5GMMMessage->u.plain->securityHeaderType = NAS5GS1540_plain5GSNASMessage;

     nasmessage->u.nas5GMMMessage->u.plain->messageType = 
						NAS5GS1540_NAS5GMMMessageType_registrationRequest;
    nasmessage->u.nas5GMMMessage->u.plain->messageBody.choice = 
						NAS5GS1540_registrationRequest_chosen;
    nasmessage->u.nas5GMMMessage->u.plain->messageBody.u.registrationRequest = 
						registrationRequest = NEW(NAS5GS1540_RegistrationRequest);

    registrationRequest->nas5GSRegistrationType.nas5GSRegistrationTypeValue = 
						NAS5GS1540_initialRegistration;
    registrationRequest->nas5GSRegistrationType.NAS5GSRegistrationType_for = 
						NAS5GS1540_followOnRequestPending;

    registrationRequest->ngKSI.tsc = NAS5GS1540_NASKeySetIdentifier_tsc_nativeSecurityContext;
    registrationRequest->ngKSI.nasKeySetIdentifier = 4;

    registrationRequest->nas5GSMobileIdentity.choice = NAS5GS1540_nas5GSTMSI_chosen;
    registrationRequest->nas5GSMobileIdentity.u.nas5GSTMSI = 
						NEW(NAS5GS1540_MobileIdentity5GSTMSI);

    registrationRequest->nas5GSMobileIdentity.u.nas5GSTMSI->amfPointer = 2;
    registrationRequest->nas5GSMobileIdentity.u.nas5GSTMSI->dummy = 15;
    registrationRequest->nas5GSMobileIdentity.u.nas5GSTMSI->amfSetID = 0;
    registrationRequest->nas5GSMobileIdentity.u.nas5GSTMSI->oddEvenIndicator = 0;
    registrationRequest->nas5GSMobileIdentity.u.nas5GSTMSI->typeOfIdentity = 4;
    SET_OSTRING_BY_LITERAL(registrationRequest->nas5GSMobileIdentity.u.nas5GSTMSI->nas5GTMSI, "\x02\x04\x17\x25");

   registrationRequest->bit_mask = NAS5GS1540_nas5GMMCapability_present
                     | NAS5GS1540_RegistrationRequest_networkSlicingIndication_present;
	registrationRequest->nas5GMMCapability.spare = 0;
    registrationRequest->nas5GMMCapability.hoAttach = NAS5GS1540_supported;
    registrationRequest->nas5GMMCapability.lpp = NAS5GS1540_lppInN1ModeSupported;
    registrationRequest->nas5GMMCapability.s1Mode = NAS5GS1540_s1ModeSupported;

    registrationRequest->networkSlicingIndication.spare = 0;
    registrationRequest->networkSlicingIndication.dcni = NAS5GS1540_requestedNSSAICreated;
    registrationRequest->networkSlicingIndication.nssci = 
						NAS5GS1540_networkSlicingSubscriptionNotChanged;

    ossNASPrint(NULL, "OK.\n");

    /* Encode the message */
    encodedData.value = env->encodedDataBuffer;
    encodedData.length = (long)(freeAddr - (unsigned char *)nasmessage);  
    ossNASPrint(NULL, "Encoding...");
    retcode = ossNASEncode(nasworld, pdu_num, nasmessage, &encodedData);

    if (retcode != 0) {
        ossNASPrint(nasworld, "ossNASEncode error: %s\n", ossNASGetErrMsg(nasworld));
        return 2;
    }
    ossNASPrint(NULL, "OK.\n");
    ossNASPrint(nasworld, "Encoding (%ld octets):\n", encodedData.length);
    printHex(nasworld, encodedData.value, encodedData.length);
    ossNASPrint(nasworld, "\n");

    /* This is the length of the encoded message produced by the ossNASEncode function */
    env->lenEncodedData = encodedData.length;

    /* Decode the encoded message produced by the ossNASEncode function */
    encodedData.value = env->encodedDataBuffer;
    encodedData.length = env->lenEncodedData;
    nasmessage = (NAS5GS1540_NASMessage *)env->decodedDataBuffer;
    ossNASSetDecodingLength(nasworld, bufferSize);  /* Size of the output buffer for the decoded message */
    ossNASPrint(NULL, "Decoding back...");

    retcode = ossNASDecode(nasworld, &pdu_num, &encodedData, (void **)&nasmessage);

    if (retcode != 0) {
        ossNASPrint(nasworld, "ossNASDecode error: %s\n", ossNASGetErrMsg(nasworld));
        return 3;
    }
    ossNASPrint(NULL, "OK.\n");

    ossNASPrint(NULL, "Comparing original and decoded messages...");
    /* Compare the decoded message produced by the ossNASDecode function
     * with the unencoded message. They are expected to be equal
     */
    retcode = ossNASCmpValue(nasworld, OSSNAS_PDUNUM, env->unencodedDataBuffer,
						env->decodedDataBuffer);

   /* Convert the encoded message to XML using the ossNASBinary2XML function */
    encodedData.value = env->encodedDataBuffer;
    encodedData.length = env->lenEncodedData;
    outData.value = env->outTextBuffer;
    outData.length = bufferSize;
    ossNASPrint(NULL, "Converting encoded message to XML...");
    retcode = ossNASBinary2XML(nasworld, OSSNAS_PDUNUM, (ossEncodingRules)0,
						&encodedData, &outData);

    if (retcode != 0) {
        ossNASPrint(nasworld, "ossNASBinary2XML error: %s\n", ossNASDescribeReturnCode(nasworld, retcode));
        return 5;
    }
    ossNASPrint(NULL, "OK.\n");

    /* Print the resulting XML text to the console */
    env->outTextBuffer[outData.length] = 0;
    ossNASPrint(NULL, "Printing the resulting XML as string...\n");

    ossNASPrint(nasworld, "%s\n\n", env->outTextBuffer);

/* We convert the encoded message to JSON using the ossNASBinary2JSON function */
	encodedData.value = encodedDataBuffer;
	encodedData.length = lenEncodedData;
	outData.value = outTextBuffer;
	outData.length = bufferSize;
	retcode = ossNASBinary2JSON(nasworld, pdu_num, OSSNAS_ENCRULE, &encodedData, &outData);

	if(retcode != 0) 
	{
		ossNASPrint(nasworld, "ossNASBinary2JSON error: %s\n", 
				ossNASDescribeReturnCode(nasworld, retcode));
		return 5;
	}			

	/* We print the resulting JSON text to the console */
	outTextBuffer[outData.length] = 0;
	ossNASPrint(nasworld, "%s\n\n", outTextBuffer);

    /* Print the decoded message (as XML text) to the console */
    /* The output is expected to match the output of the ossNASBinary2XML function */
    nasmessage = (NAS5GS1540_NASMessage *)env->decodedDataBuffer;
    ossNASPrint(NULL, "Printing decoded message using ossNASPrintPDU()...\n");
    retcode = ossNASPrintPDU(nasworld, OSSNAS_PDUNUM, nasmessage);

	return 0;
}

This documentation applies to the NAS/C Encoder Decoder Library for 5G v7.1.0 for 3GPP Release 15.4.0.

Copyright © 2020 OSS Nokalva, Inc. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means electronic, mechanical, photocopying, recording or otherwise, without the prior permission of OSS Nokalva, Inc.
Every distributed copy of the NAS/C Encoder Decoder Library for 5G is associated with a specific license and related unique license number. That license determines, among other things, what functions of the NAS/C Encoder Decoder Library for 5G are available to you.