/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000-2023 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