We'll use the PDU for TS 24.008 as our example. File TS24008Msgs.asn contains a type defined as follows:
PDU ::= SEQUENCE { -- L3 header, octet 1, bits 5 thru 8 l3HdrOpts CHOICE { skipInd INTEGER(0..15), transId SEQUENCE { flag BOOLEAN, value INTEGER(0..255) } }, protoDiscr NAS-PROTOCOL-CLASS.&protoDiscr ({TS24008-IE-OBJECTSET}), sendSeqNum INTEGER (0..3) OPTIONAL, msgType NAS-PROTOCOL-CLASS.&msgType ({TS24008-IE-OBJECTSET}), data NAS-PROTOCOL-CLASS.&Value ({TS24008-IE-OBJECTSET}{@protoDiscr,@msgType}) }
The first 4 elements within this definition (l3HdrOpts
, protoDiscr
, sendSeqNum
, and msgType
) describe header fields as defined in the TS 24.007 and TS 24.008 documents. The final data field is a variable type field that defines the contents for all of the different message types. The combination of protocol discriminator and message type serve to specify the message type.
The general procedure to encode a message of this type is as follows:
Declare variables of the generated PDU type (e.g. TS24008Msg_PDU
) and the specific message type to be sent (e.g. TS24008Msg_IdentityRequest
).
Populate the types. The address of the specific message structure would be stored within the PDU union structure. The generated asn1SetTC_*
(set table constraint) functions can be used to set fixed value fields (protocol discriminator and message type) and the pointer to the message data in one call.
Initialize the context structure and set the context buffer pointer.
Call the PDU encode function
Get the message pointer and length to work with the binary message.
Before a NAS encode function can be called, the user must first initialize an encoding context block structure. The context block is initialized by calling the rtInitContext
function.
Only memory-buffer based encoding is supported because the message sizes are generally small (normally less than 256 bytes).
To do memory-based encoding, the rtxInitContextBuffer
function would be called. This can be used to specify use of a static or dynamic memory buffer. Specification of a dynamic buffer is possible by setting the buffer address argument to null and the buffer size argument to zero.
The PDU encode function can then be called to encode the message. If the return status indicates success (0), then the message will have been encoded in the given buffer. The length of the encoded message can be obtained by calling the rtxCtxtGetMsgLen
run-time function. If dynamic encoding was specified (i.e., a buffer start address and length were not given), the rtxCtxtGetMsgPtr
run-time function can be used to obtain the start address of the message. This routine will also return the length of the encoded message.
A program fragment that could be used to encode a 3G NAS Identity Request message is as follows:
#include "rt3gppsrc/TS24008Msgs.h" /* include file generated by ASN1C */ main () { TS24008Msg_PDU pdu; TS24008Msg_IdentityRequest idReq; OSCTXT ctxt; OSOCTET msgbuf[256], *msgptr; int i, len, stat; const char* filename = "message.dat"; /* Initialize context structure */ stat = rtInitContext (&ctxt); if (0 != stat) { printf ("rtInitContext failed; status = %d\n", ret); rtxErrPrint (&ctxt); return ret; } /* Populate C structure */ pdu.l3HdrOpts.u.skipInd = 0; asn1SetTC_TS24008Msg_PDU_obj_IdentityRequest (&ctxt, &pdu, &idReq); OSCRTLMEMSET (&idReq, 0, sizeof(idReq)); idReq.value.typeOfIdent = TS24008IE_IdentityTypeValue_typeOfIdent_imei; /* Encode */ rtxCtxtSetBufPtr (&ctxt, msgbuf, sizeof(msgbuf)); stat = NASEnc_TS24008Msg_PDU (&ctxt, &pdu); if (0 != stat) { printf ("encode PDU failed; status = %d\n", ret); rtxErrPrint (&ctxt); return ret; } msgptr = rtxCtxtGetMsgPtr (&ctxt); len = rtxCtxtGetMsgLen (&ctxt); ... }