/////////////////////////////////////////////////////////////////////////////// // // 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: GTPC_EncDec.cc // Rev: R2A // Prodnr: CNL 113 843 // Contact: http://ttcn.ericsson.se // Reference: 3GPP TS 29.060 v13.5.0 #include "GTPC_Types.hh" namespace GTPC__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,GTPC__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.gTPC__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.gTPC__extensionHeader__List()()[i].lengthfield() = lengthfield; OPT_PART.gTPC__extensionHeader__List()()[i].content() = OCTETSTRING(4*lengthfield-2,opt_part_ptr + opt_part_length +1); OPT_PART.gTPC__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; } void dec__PDU__GTPC_no_optional_part(const unsigned char * udp__pdu,const int pl_udp_pdu_length, const SystemUnderTest& pl__SystemUnderTest,PDU__GTPC& pdu) { TTCN_Buffer buf; if ((pl__SystemUnderTest == SystemUnderTest::GGSN) || (pl__SystemUnderTest == SystemUnderTest::CGW)) // testing GGSN or CGW (not default) { const unsigned char *gtpc_message = (const unsigned char *) udp__pdu; if ((gtpc_message[1] == 0x12) || (gtpc_message[1] == 0x13)) // if updatePDPContextRequest or updatePDPContextResponse message is received from GGSN or C-GW { unsigned char pn = gtpc_message[0] & 0x01; pdu.pn__bit() = BITSTRING(1,&pn); unsigned char s = (gtpc_message[0] & 0x02) >> 1; pdu.s__bit() = BITSTRING(1,&s); unsigned char e = (gtpc_message[0] & 0x04) >> 2; pdu.e__bit() = BITSTRING(1,&e); unsigned char spare = (gtpc_message[0] & 0x08) >> 3; pdu.spare() = BITSTRING(1,&spare ); unsigned char pt = (gtpc_message[0] & 0x10) >> 4; pdu.pt() = BITSTRING(1,&pt ); unsigned char version = ((gtpc_message[0] & 0x80) >> 7) | ((gtpc_message[0] & 0x40) >> 5) | ((gtpc_message[0] & 0x20) >> 3) ; pdu.version() = BITSTRING(3,&version); pdu.messageType() = OCTETSTRING(1,gtpc_message+1); pdu.lengthf() = (gtpc_message[2] << 8) + gtpc_message[3]; pdu.teid() = OCTETSTRING(4,gtpc_message+4); pdu.opt__part() = OMIT_VALUE; if (gtpc_message[1] == 0x12) //updatePDPContextRequest { if(pl__SystemUnderTest == SystemUnderTest::GGSN) // from GGSN { UpdatePDPContextRequestGGSN updatePDPContextRequestGGSN; OCTETSTRING updatePDPContextRequestGGSN_string = OCTETSTRING(pl_udp_pdu_length-8,udp__pdu+8 ); buf.put_os(updatePDPContextRequestGGSN_string); updatePDPContextRequestGGSN.decode(UpdatePDPContextRequestGGSN_descr_,buf,TTCN_EncDec::CT_RAW); pdu.gtpc__pdu().updatePDPContextRequest().updatePDPContextRequestGGSN() = updatePDPContextRequestGGSN; } else // from CGW { UpdatePDPContextRequestCGW updatePDPContextRequestCGW; OCTETSTRING updatePDPContextRequestCGW_string = OCTETSTRING(pl_udp_pdu_length-8,udp__pdu+8 ); buf.put_os(updatePDPContextRequestCGW_string); updatePDPContextRequestCGW.decode(UpdatePDPContextRequestCGW_descr_,buf,TTCN_EncDec::CT_RAW); pdu.gtpc__pdu().updatePDPContextRequest().updatePDPContextRequestCGW() = updatePDPContextRequestCGW; } } else //updatePDPContextResponse { if(pl__SystemUnderTest == SystemUnderTest::GGSN) // from GGSN { UpdatePDPContextResponseGGSN updatePDPContextResponseGGSN; OCTETSTRING updatePDPContextResponseGGSN_string = OCTETSTRING(pl_udp_pdu_length-8,udp__pdu+8 ); buf.put_os(updatePDPContextResponseGGSN_string); updatePDPContextResponseGGSN.decode(UpdatePDPContextResponseGGSN_descr_,buf,TTCN_EncDec::CT_RAW); pdu.gtpc__pdu().updatePDPContextResponse().updatePDPContextResponseGGSN() = updatePDPContextResponseGGSN; } else // from CGW { UpdatePDPContextResponseCGW updatePDPContextResponseCGW; OCTETSTRING updatePDPContextResponseCGW_string = OCTETSTRING(pl_udp_pdu_length-8,udp__pdu+8 ); buf.put_os(updatePDPContextResponseCGW_string); updatePDPContextResponseCGW.decode(UpdatePDPContextResponseCGW_descr_,buf,TTCN_EncDec::CT_RAW); pdu.gtpc__pdu().updatePDPContextResponse().updatePDPContextResponseCGW() = updatePDPContextResponseCGW; } } buf.clear(); return; } else // if message not equal to updatePDPContextRequest or updatePDPContextResponse is received from GGSN or C-GW { buf.put_s(pl_udp_pdu_length,udp__pdu); pdu.decode(PDU__GTPC_descr_, buf, TTCN_EncDec::CT_RAW); buf.clear(); return; } } else //pl__SystemUnderTest is SGSN or MME (this is default) { buf.put_s(pl_udp_pdu_length,udp__pdu); pdu.decode(PDU__GTPC_descr_, buf, TTCN_EncDec::CT_RAW); buf.clear(); return; } } ////////////////////////////////// // Decoding function for GTPC__DialoguePDU ////////////////////////////////// PDU__GTPC dec__PDU__GTPC(const OCTETSTRING& udp__pdu,const SystemUnderTest& pl__SystemUnderTest) { PDU__GTPC pdu; const unsigned char *gtpc_message = (const unsigned char *) udp__pdu; int opt_part_length = 0; if ( gtpc_message[0] & 0x07 ) // opt_part is present { GTPC__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(gtpc_message+8,OPT_PART); if( ((gtpc_message[2] << 8) + gtpc_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 gtpc_IEs_length = (gtpc_message[2] << 8) + gtpc_message[3] - opt_part_length; unsigned char gtpcBuf[8 + gtpc_IEs_length]; memcpy(gtpcBuf,gtpc_message,8); memcpy(gtpcBuf+8,gtpc_message+8+opt_part_length,gtpc_IEs_length); // substitute dummy bits (indicating there is no optional part) gtpcBuf[0] = gtpcBuf[0] & 0xf8; // substitute dummy length (not including optional part) gtpcBuf[2] = (gtpc_IEs_length & 0xff00) >> 8; gtpcBuf[3] = gtpc_IEs_length & 0xff; // call decoding function dec__PDU__GTPC_no_optional_part(gtpcBuf,udp__pdu.lengthof() - opt_part_length,pl__SystemUnderTest,pdu); // put back the original values unsigned char pn = gtpc_message[0] & 0x01; pdu.pn__bit() = BITSTRING(1,&pn); unsigned char s = (gtpc_message[0] & 0x02) >> 1; pdu.s__bit() = BITSTRING(1,&s); unsigned char e = (gtpc_message[0] & 0x04) >> 2; pdu.e__bit() = BITSTRING(1,&e); pdu.lengthf() = (gtpc_message[2] << 8) + gtpc_message[3]; pdu.opt__part() = OPT_PART; return pdu; } else // opt_part is not present { dec__PDU__GTPC_no_optional_part(gtpc_message,udp__pdu.lengthof(),pl__SystemUnderTest,pdu); return pdu; } } // end of function }//namespace