blob: 579e14a3ae82c9eb6edb63f37229e87e8df69596 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2019 Ericsson Telecom AB
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v2.0
// which accompanies this distribution, and is available at
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
///////////////////////////////////////////////////////////////////////////////
//
// File: GTPU_EncDec.cc
// Rev: R2A
// Prodnr: CNL 113 843
// Contact: http://ttcn.ericsson.se
// Reference: 3GPP TS 29.060 v13.5.0
#include "GTPU_Types.hh"
namespace GTPU__Types {
// find the length of the optional part and decode optional part into OPT_PART
int find_optpart_length(const unsigned char * opt_part_ptr,GTPU__Header__optional__part& OPT_PART)// pointer to opt part start
{
int opt_part_length = 4; // mandatory minimum length of opt_part
OPT_PART.sequenceNumber() = OCTETSTRING(2,opt_part_ptr);
OPT_PART.npduNumber() = OCTETSTRING(1,opt_part_ptr+2);
OPT_PART.nextExtHeader() = OCTETSTRING(1,opt_part_ptr+3);
OPT_PART.gTPU__extensionHeader__List() = OMIT_VALUE;
int i = 0;
bool opt_part_end = false;
while(!opt_part_end)
{
if (opt_part_ptr[opt_part_length-1] != 0x00) // 0x00 means end of optional part
{
unsigned char lengthfield = opt_part_ptr[opt_part_length];
OPT_PART.gTPU__extensionHeader__List()()[i].lengthfield() = lengthfield;
OPT_PART.gTPU__extensionHeader__List()()[i].content() =
OCTETSTRING(4*lengthfield-2,opt_part_ptr + opt_part_length +1);
OPT_PART.gTPU__extensionHeader__List()()[i].nextExtHeader() =
OCTETSTRING(1,opt_part_ptr + opt_part_length + 4*lengthfield - 1);
opt_part_length = opt_part_length + 4*lengthfield;
i++;
}
else
{opt_part_end = true;}
}
return opt_part_length;
}
//////////////////////////////////
// Decoding function for GTPC__DialoguePDU
//////////////////////////////////
PDU__GTPU dec__PDU__GTPU(const OCTETSTRING& udp__pdu)
{
TTCN_Buffer buf;
PDU__GTPU pdu;
const unsigned char *gtpu_message = (const unsigned char *) udp__pdu;
int opt_part_length = 0;
if ( gtpu_message[0] & 0x07 ) // opt_part is present
{
GTPU__Header__optional__part OPT_PART;
// find the length of the optional part and decode optional part into OPT_PART
opt_part_length = find_optpart_length(gtpu_message+8,OPT_PART);
if( ((gtpu_message[2] << 8) + gtpu_message[3] - opt_part_length) < 0 )
{TTCN_error("Decoding error, lengthf field is shorter that decoded length of opt_part");};
// build PDU without optional part
unsigned int gtpu_IEs_length = (gtpu_message[2] << 8) + gtpu_message[3] - opt_part_length;
unsigned char gtpuBuf[8 + gtpu_IEs_length];
memcpy(gtpuBuf,gtpu_message,8);
memcpy(gtpuBuf+8,gtpu_message+8+opt_part_length,gtpu_IEs_length);
// substitute dummy bits (indicating there is no optional part)
gtpuBuf[0] = gtpuBuf[0] & 0xf8;
// substitute dummy length (not including optional part)
gtpuBuf[2] = (gtpu_IEs_length & 0xff00) >> 8;
gtpuBuf[3] = gtpu_IEs_length & 0xff;
// RAW decoding
buf.put_s(8 + gtpu_IEs_length,gtpuBuf);
pdu.decode(PDU__GTPU_descr_, buf, TTCN_EncDec::CT_RAW);
buf.clear();
// put back the original values
unsigned char pn = gtpu_message[0] & 0x01;
pdu.pn__bit() = BITSTRING(1,&pn);
unsigned char s = (gtpu_message[0] & 0x02) >> 1;
pdu.s__bit() = BITSTRING(1,&s);
unsigned char e = (gtpu_message[0] & 0x04) >> 2;
pdu.e__bit() = BITSTRING(1,&e);
pdu.lengthf() = (gtpu_message[2] << 8) + gtpu_message[3];
pdu.opt__part() = OPT_PART;
return pdu;
}
else // opt_part is not present
{
buf.put_os(udp__pdu);
pdu.decode(PDU__GTPU_descr_, buf, TTCN_EncDec::CT_RAW);
buf.clear();
return pdu;
}
} // end of function
}//namespace