diff --git a/L2TP_CNL113603.tpd b/L2TP_CNL113603.tpd new file mode 100644 index 0000000000000000000000000000000000000000..8df361133db3b3817e0078b632a63f88df8f5566 --- /dev/null +++ b/L2TP_CNL113603.tpd @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2015 Ericsson + + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + + File: L2TP_CNL113603.tpd + Description: tpd project file + Rev: R2A + Prodnr: CNL 113 603 + + --> +<TITAN_Project_File_Information version="1.0"> + <ProjectName>L2TP_CNL113603</ProjectName> + <ReferencedProjects> + <ReferencedProject name="ProtocolModules_Common" projectLocationURI="../COMMON/ProtocolModules_Common.tpd"/> + </ReferencedProjects> + <Folders> + <FolderResource projectRelativePath="src" relativeURI="src"/> + </Folders> + <Files> + <FileResource projectRelativePath="src/L2TP_EncDec.cc" relativeURI="src/L2TP_EncDec.cc"/> + <FileResource projectRelativePath="src/L2TP_Types.ttcn" relativeURI="src/L2TP_Types.ttcn"/> + </Files> + <ActiveConfiguration>Default</ActiveConfiguration> + <Configurations> + <Configuration name="Default"> + <ProjectProperties> + <MakefileSettings> + <generateInternalMakefile>true</generateInternalMakefile> + <GNUMake>true</GNUMake> + <incrementalDependencyRefresh>true</incrementalDependencyRefresh> + <targetExecutable>bin/L2TP_CNL113603</targetExecutable> + </MakefileSettings> + <LocalBuildSettings> + <workingDirectory>bin</workingDirectory> + </LocalBuildSettings> + <NamingCoventions> + <enableProjectSpecificSettings>true</enableProjectSpecificSettings> + <function>.*</function> + <externalFunction>.*</externalFunction> + <moduleParameter>.*</moduleParameter> + <formalParameter>.*</formalParameter> + </NamingCoventions> + </ProjectProperties> + </Configuration> + </Configurations> +</TITAN_Project_File_Information> diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1862125dbbe2a2817aaab5874b65e8c13367c777 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# titan.ProtocolModules.L2TP + +Main project page: + +https://projects.eclipse.org/projects/tools.titan + +The source code of the TTCN-3 compiler and executor: + +https://github.com/eclipse/titan.core diff --git a/doc/L2TP_CNL113603_FS.doc b/doc/L2TP_CNL113603_FS.doc new file mode 100644 index 0000000000000000000000000000000000000000..8c2818428ed4c744a3112fb4f5e294ded4212706 Binary files /dev/null and b/doc/L2TP_CNL113603_FS.doc differ diff --git a/doc/L2TP_CNL113603_PRI.doc b/doc/L2TP_CNL113603_PRI.doc new file mode 100644 index 0000000000000000000000000000000000000000..9830fd029cdc69a2a45feec154ff4792d081b431 Binary files /dev/null and b/doc/L2TP_CNL113603_PRI.doc differ diff --git a/doc/L2TP_CNL113603_UG.doc b/doc/L2TP_CNL113603_UG.doc new file mode 100644 index 0000000000000000000000000000000000000000..686c254b8eadb7e0a0d3689c72ac2daea47b8025 Binary files /dev/null and b/doc/L2TP_CNL113603_UG.doc differ diff --git a/src/L2TP_EncDec.cc b/src/L2TP_EncDec.cc new file mode 100644 index 0000000000000000000000000000000000000000..3f2c90b2b1e4a079c87d7db18ca50e52001b69b8 --- /dev/null +++ b/src/L2TP_EncDec.cc @@ -0,0 +1,312 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Endre Kulcsar +* Gabor Szalai +******************************************************************************/ +// +// File: L2TP_EncDec.cc +// Rev: R2A +// Prodnr: CNL 113 603 +// Reference: RFC 2661 +// +/////////////////////////////////////////////////////////////////////////////// + +#include "L2TP_Types.hh" + +#include <openssl/md5.h> +#include <time.h> + +namespace L2TP__Types { + +#define CTRL_MSG_HDR_LENGTH 20 +// Length of L2TP control message header (Length,Nr and Ns fields are mandatory) + Length of Message Type AVP + + +// calculates 16 bit MD5 message digest +unsigned char * calc_MD5(OCTETSTRING& pl_input, int pl_size, unsigned char * output) + { + MD5(pl_input,(size_t) pl_size,output); + return output; + } + +OCTETSTRING enc__PDU__L2TP(const PDU__L2TP& pdu) +{ + if (TTCN_Logger::log_this_event(TTCN_DEBUG)) { + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("Encoding PDU_L2TP: "); + pdu.log(); + TTCN_Logger::end_event(); + } + + TTCN_Buffer buf; + pdu.encode(PDU__L2TP_descr_, buf, TTCN_EncDec::CT_RAW); + + // ret_val is the RAW encoded PDU without any AVP Hiding + // if there are no H_BITs equal to 1 this will be returned from enc__PDU__L2TP + OCTETSTRING ret_val(buf.get_len(), buf.get_data()); + + // only control msgs use hiding (tBit = 1) + const unsigned char *T_BIT = pdu.header().tBit(); + if (*T_BIT && (ret_val.lengthof() >= CTRL_MSG_HDR_LENGTH)) // if ctrl message and not ZLB + { + OCTETSTRING ret_val_ctrl_msg = substr(ret_val,0,CTRL_MSG_HDR_LENGTH); // copy original msg header + + const unsigned char * avp_length; + unsigned int avp_length_int; + const unsigned char * avp_type; + //unsigned int avp_type_int; + unsigned int index = CTRL_MSG_HDR_LENGTH; + //unsigned int index_rv = CTRL_MSG_HDR_LENGTH; + bool H_BIT; + OCTETSTRING AVP_TYPE; + OCTETSTRING AVP_HEADER; + OCTETSTRING AVP_VALUE; + OCTETSTRING AVP_LENGTH; + const unsigned char header_mask[2] = {0xfc, 0x00}; + unsigned char avp_hidden_length[2]; + srand((unsigned)time(0)); + + while (index < buf.get_len() ) + { + avp_length = ((const unsigned char *)ret_val) + index; + H_BIT = ((avp_length[0] & 0x40) >> 6); // H_BIT = 1 -> hiding is needed for this AVP + avp_length_int = ((avp_length[0] & 0x03) << 8) + avp_length[1]; // length of AVP + AVP_LENGTH = int2oct(avp_length_int-6,2); + AVP_HEADER = substr(ret_val,index,6); + avp_type = ((const unsigned char *)ret_val)+ index+4; + AVP_TYPE = OCTETSTRING(2,avp_type); + AVP_VALUE = substr(ret_val,index+6,avp_length_int-6); + OCTETSTRING AVP_VALUE_HIDDEN(0,NULL); + //avp_type_int = (avp_type[0] << 8) + avp_type[1]; + unsigned int index_rv = CTRL_MSG_HDR_LENGTH; + + if (H_BIT == TRUE) // hidden AVP is needed + { + bool bound_flag = FALSE; + OCTETSTRING random_vector; + + // find random vector "most closely preceding" + while (index_rv < index ) + { + const unsigned char *avp_length_find_rv = ((const unsigned char *)ret_val)+index_rv; + unsigned int avp_length_int_find_rv = ((avp_length_find_rv[0] & 0x03) << 8) + avp_length_find_rv[1]; // length of AVP + + const unsigned char *avp_type_find_rv = ((const unsigned char *)ret_val) + index_rv+4; + unsigned int avp_type_int_find_rv = (avp_type_find_rv[0] << 8) + avp_type_find_rv[1]; + + if (avp_type_int_find_rv == 36) // if AVP's Attr type is rand vect + { + random_vector = substr(ret_val,index_rv+6,avp_length_int_find_rv-6); + bound_flag = TRUE; + } + + index_rv = index_rv + avp_length_int_find_rv; // points to start of next AVP in original stream + } + + if (bound_flag == FALSE) // random_vector.is_bound() == NULL + {TTCN_error("%s","No Random Vector AVP present");} // Error: No Random Vector AVP before Hidden AVP! + + // Calculate RANDOM_PADDING needed for HIDDEN_AVP_SUBFORMAT + int random = rand(); + OCTETSTRING HIDDEN_AVP_SUBFORMAT; + if ( (random % (tsp__Max__Random__Padding__Length+1)) == 0 ) + { + HIDDEN_AVP_SUBFORMAT = AVP_LENGTH + AVP_VALUE; + } + else + { + OCTETSTRING RANDOM_PADDING(int2oct(0,random % (tsp__Max__Random__Padding__Length+1))); + HIDDEN_AVP_SUBFORMAT = AVP_LENGTH + AVP_VALUE + RANDOM_PADDING; + } + + // AVP padded to exact multiple of 16 + int avp_padding_length = 16 -(HIDDEN_AVP_SUBFORMAT.lengthof() % 16 ); + unsigned char padding[avp_padding_length]; + for(int i = 0; i < avp_padding_length; i++) + {padding[i] = 0x00;} + OCTETSTRING AVP_PADDING = OCTETSTRING(avp_padding_length,padding); + OCTETSTRING AVP_VALUE_PADDED = HIDDEN_AVP_SUBFORMAT + AVP_PADDING; + + // CONCATENATION is input into HIDE procedure + OCTETSTRING CONCATENATION = AVP_TYPE + tsp__L2TP__SharedSecret + random_vector; + + // HIDE PROCEDURE + OCTETSTRING b; + OCTETSTRING c; + unsigned char MD5_value[16]; + for (int j = 0; j < (AVP_VALUE_PADDED.lengthof()) ; j=j+16) + { + b = OCTETSTRING(16,(const unsigned char *)calc_MD5(CONCATENATION,CONCATENATION.lengthof(),MD5_value)); + c = ((substr(AVP_VALUE_PADDED,j ,16 )) ^ b); + CONCATENATION = tsp__L2TP__SharedSecret + c; + AVP_VALUE_HIDDEN = AVP_VALUE_HIDDEN + c; + } + + // modify length field in AVP_HEADER to actual length of hidden AVP + unsigned int avp_hidden_length_int = 6 + AVP_VALUE_HIDDEN.lengthof(); + avp_hidden_length[0] = (avp_hidden_length_int & 0x0300)>> 8; + avp_hidden_length[1] = (avp_hidden_length_int & 0xff); + unsigned char* avp_header2 = (unsigned char*)(const unsigned char*)AVP_HEADER; + avp_header2[0] &= header_mask[0]; + avp_header2[1] &= header_mask[1]; + avp_header2[0] |= avp_hidden_length[0]; + avp_header2[1] |= avp_hidden_length[1]; + + ret_val_ctrl_msg = ret_val_ctrl_msg + AVP_HEADER + AVP_VALUE_HIDDEN; // Add new hidden AVP + } + else // original (not hidden) AVP is used because for this AVP H_BIT == FALSE + { + ret_val_ctrl_msg = ret_val_ctrl_msg + substr(ret_val,index,avp_length_int); + } + index = index + avp_length_int; // points to start of next AVP in original stream + } // end of while (index < buf.get_len() ) + + ret_val = ret_val_ctrl_msg; + } // end of if (*T_BIT) + + //fill in true length of complete PDU if lengthValue field is present + if (pdu.header().lengthValue().ispresent()) + { + unsigned int PDU_SIZE_INT = ret_val.lengthof(); + unsigned char PDU_SIZE_CHAR[2]; + PDU_SIZE_CHAR[0] = (PDU_SIZE_INT & 0xff00) >> 8; + PDU_SIZE_CHAR[1] = (PDU_SIZE_INT & 0xff ); + + OCTETSTRING PDU_SIZE_OCTETSTRING(2, PDU_SIZE_CHAR); + + ret_val = substr(ret_val,0,2) + PDU_SIZE_OCTETSTRING + substr(ret_val,4,PDU_SIZE_INT-4); + } + + if (TTCN_Logger::log_this_event(TTCN_DEBUG)) { + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("Encoded PDU_L2TP: "); + ret_val.log(); + TTCN_Logger::end_event(); + } + return ret_val; +} + +PDU__L2TP dec__PDU__L2TP(const OCTETSTRING& stream) +{ + if (TTCN_Logger::log_this_event(TTCN_DEBUG)) { + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("Decoding PDU_L2TP: "); + stream.log(); + TTCN_Logger::end_event(); + } + TTCN_Buffer buf; + + // if control message check AVPs whether hiding was used + if ((((((const unsigned char *)stream)[0]) & 0x80) == 0x80) && (stream.lengthof() >= CTRL_MSG_HDR_LENGTH)) // if control message and not ZLB + { + OCTETSTRING stream_ctrl_msg = substr(stream,0,CTRL_MSG_HDR_LENGTH); // copy original msg header + unsigned int index = CTRL_MSG_HDR_LENGTH; + //unsigned int index_rv = CTRL_MSG_HDR_LENGTH; + const unsigned char * avp_length; + unsigned avp_length_int; + //unsigned avp_length_int_orig; + bool H_BIT; + while (index < (unsigned int)stream.lengthof() ) + { + avp_length = ((const unsigned char *)stream) + index; + H_BIT = ((avp_length[0] & 0x40) >> 6); //if H_BIT = 1 -> hiding was used for this AVP + avp_length_int = ((avp_length[0] & 0x03) << 8) + avp_length[1]; // length of AVP + //avp_length_int_orig = avp_length_int; + OCTETSTRING AVP_HEADER = substr(stream,index,6); + const unsigned char header_mask[2] = {0xfc, 0x00}; + unsigned char* avp_hidden_length; //[2]; + unsigned int index_rv = CTRL_MSG_HDR_LENGTH; + + if (H_BIT == TRUE) // hiding was used for this AVP + { + bool bound_flag = FALSE; + OCTETSTRING random_vector; + + // find random vector "most closely preceding" + OCTETSTRING HIDDEN_AVP_SUBFORMAT(0,NULL); + while (index_rv < index ) + { + const unsigned char *avp_length_find_rv = ((const unsigned char *)stream)+index_rv; + unsigned int avp_length_int_find_rv = ((avp_length_find_rv[0] & 0x03) << 8) + avp_length_find_rv[1]; // length of AVP + + const unsigned char *avp_type_find_rv = ((const unsigned char *)stream) + index_rv+4; + unsigned int avp_type_int_find_rv = (avp_type_find_rv[0] << 8) + avp_type_find_rv[1]; + + if (avp_type_int_find_rv == 36) // if AVP's Attr type is rand vect + { + random_vector = substr(stream,index_rv+6,avp_length_int_find_rv-6); + bound_flag = TRUE; + } + index_rv = index_rv + avp_length_int_find_rv; // points to start of next AVP in original stream + } + if (bound_flag == FALSE) + {TTCN_error("%s","No Random Vector AVP present");} // Error: No Random Vector AVP before Hidden AVP! + + // CONCATENATION is input into HIDE procedure + OCTETSTRING CONCATENATION; + const unsigned char *avp_type = ((const unsigned char *)stream) + index+4; //type of AVP + OCTETSTRING AVP_TYPE = OCTETSTRING(2,avp_type); + unsigned char MD5_value[16]; + OCTETSTRING b; + OCTETSTRING p; + unsigned int j = index + avp_length_int-32; + + while(j >= (index + 6)) + { + CONCATENATION = tsp__L2TP__SharedSecret + substr(stream,j,16); + b = OCTETSTRING(16,(const unsigned char *)calc_MD5(CONCATENATION,CONCATENATION.lengthof(),MD5_value)); + p = b ^ substr(stream,j + 16,16); + HIDDEN_AVP_SUBFORMAT = p + HIDDEN_AVP_SUBFORMAT; + j = j-16; + } + CONCATENATION = AVP_TYPE + tsp__L2TP__SharedSecret + random_vector; + b = OCTETSTRING(16,(const unsigned char *)calc_MD5(CONCATENATION,CONCATENATION.lengthof(),MD5_value)); + p = b ^ substr(stream,index + 6,16); + HIDDEN_AVP_SUBFORMAT = p + HIDDEN_AVP_SUBFORMAT; + + // modify length field in AVP_HEADER to actual length of hidden AVP + avp_hidden_length = (unsigned char*)(const unsigned char*)HIDDEN_AVP_SUBFORMAT; + unsigned int avp_length_int_unhidden = 6 + (((avp_hidden_length[0] & 0x03) << 8) + avp_hidden_length[1]); // complete length of AVP + unsigned int avp_length_int_unhidden_copy = avp_length_int_unhidden; + unsigned char* avp_header2 = (unsigned char*)(const unsigned char*)AVP_HEADER; + avp_header2[0] &= header_mask[0]; + avp_header2[1] &= header_mask[1]; + avp_header2[0] |= ((avp_length_int_unhidden & 0x0300)>> 8); + avp_header2[1] |= (avp_length_int_unhidden & 0xff); + + stream_ctrl_msg = stream_ctrl_msg + AVP_HEADER + substr(HIDDEN_AVP_SUBFORMAT,2,avp_length_int_unhidden_copy-6); + + } // end of if (H_BIT == TRUE) + else // original (not hidden) AVP is used because for this AVP H_BIT == FALSE + { + stream_ctrl_msg = stream_ctrl_msg + substr(stream,index,avp_length_int); + } + index = index + avp_length_int; + } // end of while + buf.put_os(stream_ctrl_msg); + } // end of if control message + + else // user data message + { + buf.put_os(stream); + } + + PDU__L2TP ret_val; + ret_val.decode(PDU__L2TP_descr_, buf, TTCN_EncDec::CT_RAW); + + if (TTCN_Logger::log_this_event(TTCN_DEBUG)) { + TTCN_Logger::begin_event(TTCN_DEBUG); + TTCN_Logger::log_event("Decoded PDU_L2TP: "); + ret_val.log(); + TTCN_Logger::end_event(); + } + return ret_val; + } // end of function dec__PDU__L2TP + +} // end of module diff --git a/src/L2TP_Types.ttcn b/src/L2TP_Types.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..c7773264ccc7d8ad27f7eff0ddc4ac9daa1664a3 --- /dev/null +++ b/src/L2TP_Types.ttcn @@ -0,0 +1,812 @@ +/****************************************************************************** +* Copyright (c) 2008, 2015 Ericsson AB +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Endre Kulcsar +* Gabor Szalai +******************************************************************************/ +// +// File: L2TP_Types.ttcn +// Rev: R2A +// Prodnr: CNL 113 603 +// Reference: RFC 2661 +// +/////////////////////////////////////////////////////////////////////////////// + +module L2TP_Types +{ + import from General_Types all; + + external function enc_PDU_L2TP(in PDU_L2TP pdu) return octetstring + + external function dec_PDU_L2TP(in octetstring stream) return PDU_L2TP + + modulepar + { + octetstring tsp_L2TP_SharedSecret := '00000000'O; + //This value is needed for hiding of AVPs + + Random_Padding_Length tsp_Max_Random_Padding_Length := 10; + // Determines the max number of Random additional octets used to obscure length + // of the Attribute Value that is being hidden. See RFC 2661 section 4.3. + // Its value is an integer larger than or equal to 0, (Padding value is all zeros) + } + + type integer Random_Padding_Length (0..infinity); + + type integer INT2_BO_LAST (0..65535) with { variant "FIELDLENGTH(16), COMP(nosign), BYTEORDER(last)" }; + + type record AVP_Header + { BIT1 mBit, + BIT1 hBit, + BIT4 reserved, + integer lengthValue, + INT2_BO_LAST vendorId, // 0 + INT2_BO_LAST attributeType + } with { + variant (mBit,hBit,reserved,lengthValue) "FIELDORDER(msb)"; + variant (lengthValue) "BYTEORDER(last)"; + variant (lengthValue) "FIELDLENGTH(10)"; + } + + // AVPs ============================================================== + + type record MessageTypeAVP + { + AVP_Header aVP_Header, // type 0 + INT2_BO_LAST messageTypeValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 0)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,messageTypeValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record RandomVectorAVP + { + AVP_Header aVP_Header, // type 36 + octetstring randomOctetString + } with { + variant "PRESENCE(aVP_Header.attributeType = 36)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,randomOctetString)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ResultCodeAVP + { + AVP_Header aVP_Header, // type 1 + INT2_BO_LAST resultCode, + INT2_BO_LAST errorCode optional, + charstring errorMessage optional + } with { + variant "PRESENCE(aVP_Header.attributeType = 1)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,resultCode,errorCode,errorMessage)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ProtocolVersionAVP + { + AVP_Header aVP_Header, // type 2 + INT1 ver, //1 + INT1 rev //0 + } with { + variant "PRESENCE(aVP_Header.attributeType = 2)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,ver,rev)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record FramingCapabilitiesAVP + { + AVP_Header aVP_Header, // type 3 + bitstring reserved length (30), + BIT1 aBit, + BIT1 sBit + } with { + variant "PRESENCE(aVP_Header.attributeType = 3)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,reserved,aBit,sBit)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + variant (reserved) "FIELDLENGTH(30)"; + variant (reserved,aBit,sBit) "FIELDORDER(msb)"; + } + + type record BearerCapabilitiesAVP + { + AVP_Header aVP_Header, // type 4 + bitstring reserved length (30), + BIT1 aBit, + BIT1 dBit + } with { + variant "PRESENCE(aVP_Header.attributeType = 4)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,reserved,aBit,dBit)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + variant (reserved) "FIELDLENGTH(30)"; + variant (reserved,aBit,dBit) "FIELDORDER(msb)"; + } + + type record TieBreakerAVP + { + AVP_Header aVP_Header, // type 5 + OCT8 tIEBreakValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 5)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,tIEBreakValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record FirmwareRevisionAVP + { + AVP_Header aVP_Header, // type 6 + INT2_BO_LAST firmwareRevisionValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 6)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,firmwareRevisionValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record HostNameAVP + { + AVP_Header aVP_Header, // type 7 + charstring hostNameValue length (1..infinity) + } with { + variant "PRESENCE(aVP_Header.attributeType = 7)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,hostNameValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record VendorNameAVP + { + AVP_Header aVP_Header, // type 8 + charstring vendorNameValue //length (0..infinity) + } with { + variant "PRESENCE(aVP_Header.attributeType = 8)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,vendorNameValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record AssignedTunnelIdAVP + { + AVP_Header aVP_Header, // type 9 + INT2_BO_LAST assignedTunnelIdValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 9)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,assignedTunnelIdValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ReceiveWindowSizeAVP + { + AVP_Header aVP_Header, // type 10 + INT2_BO_LAST windowSizeValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 10)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,windowSizeValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ChallengeAVP + { + AVP_Header aVP_Header, // type 11 + octetstring challengeValue length (1..infinity) + } with { + variant "PRESENCE(aVP_Header.attributeType = 11)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,challengeValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ChallengeResponseAVP + { + AVP_Header aVP_Header, // type 13 + OCT16 challengeResponseValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 13)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,challengeResponseValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record Q931CauseCodeAVP + { + AVP_Header aVP_Header, // type 12 + OCT2 causeCode, + OCT1 causeMsg, + charstring advisoryMsg optional + } with { + variant "PRESENCE(aVP_Header.attributeType = 12)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,causeCode,causeMsg,advisoryMsg)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record AssignedSessionIdAVP + { + AVP_Header aVP_Header, // type 14 + INT2_BO_LAST assignedSessionIdValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 14)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,assignedSessionIdValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record CallSerialNumberAVP + { + AVP_Header aVP_Header, // type 15 + OCT4 callSerialNumberValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 15)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,callSerialNumberValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record MinimumBPSAVP + { + AVP_Header aVP_Header, // type 16 + OCT4 mimimumBPSValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 16)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,mimimumBPSValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record MaximumBPSAVP + { + AVP_Header aVP_Header, // type 17 + OCT4 maximumBPSValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 17)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,maximumBPSValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record BearerTypeAVP + { + AVP_Header aVP_Header, // type 18 + bitstring reserved length (30), + BIT1 aBit, + BIT1 dBit + } with { + variant "PRESENCE(aVP_Header.attributeType = 18)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,reserved,aBit,dBit)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + variant (reserved) "FIELDLENGTH(30)"; + variant (reserved,aBit,dBit) "FIELDORDER(msb)"; + } + + type record FramingTypeAVP + { + AVP_Header aVP_Header, // type 19 + bitstring reserved length (30), + BIT1 aBit, + BIT1 sBit + } with { + variant "PRESENCE(aVP_Header.attributeType = 19)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,reserved,aBit,sBit)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + variant (reserved) "FIELDLENGTH(30)"; + variant (reserved,aBit,sBit) "FIELDORDER(msb)"; + } + + type record CalledNumberAVP + { + AVP_Header aVP_Header, // type 21 + charstring calledNumberValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 21)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,calledNumberValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record CallingNumberAVP + { + AVP_Header aVP_Header, // type 22 + charstring callingNumberValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 22)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,callingNumberValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record SUB_AddressAVP + { + AVP_Header aVP_Header, // type 23 + charstring sUB_AddressValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 23)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,sUB_AddressValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record TxConnectSpeedAVP + { + AVP_Header aVP_Header, // type 24 + OCT4 bPS + } with { + variant "PRESENCE(aVP_Header.attributeType = 24)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,bPS)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record RxConnectSpeedAVP + { + AVP_Header aVP_Header, // type 38 + OCT4 bPS + } with { + variant "PRESENCE(aVP_Header.attributeType = 38)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,bPS)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record PhysicalChannelIdAVP + { + AVP_Header aVP_Header, // type 25 + OCT4 physicalChannelIdValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 25)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,physicalChannelIdValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record PrivateGroupIdAVP + { + AVP_Header aVP_Header, // type 37 + octetstring privateGroupIdValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 37)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,privateGroupIdValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record SequencingRequiredAVP + { + AVP_Header aVP_Header // type 39 + } with { + variant "PRESENCE(aVP_Header.attributeType = 39)"; + variant (aVP_Header) "LENGTHTO(aVP_Header)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record InitialReceivedLCP_CONFREQ_AVP + { + AVP_Header aVP_Header, // type 26 + octetstring lCP_CONFREQ // structure ? + } with { + variant "PRESENCE(aVP_Header.attributeType = 26)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,lCP_CONFREQ)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record LastSentLCP_CONFREQ_AVP + { + AVP_Header aVP_Header, // type 27 + octetstring lCP_CONFREQ // structure ? + } with { + variant "PRESENCE(aVP_Header.attributeType = 27)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,lCP_CONFREQ)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record LastReceivedLCP_CONFREQ_AVP + { + AVP_Header aVP_Header, // type 28 + octetstring lCP_CONFREQ // structure ? + } with { + variant "PRESENCE(aVP_Header.attributeType = 28)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,lCP_CONFREQ)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ProxyAuthenTypeAVP + { + AVP_Header aVP_Header, // type 29 + INT2_BO_LAST authenTypeValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 29)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,authenTypeValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ProxyAuthenNameAVP + { + AVP_Header aVP_Header, // type 30 + charstring authenNameValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 30)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,authenNameValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ProxyAuthenChallengeAVP + { + AVP_Header aVP_Header, // type 31 + octetstring challengeValue length (1..infinity) + } with { + variant "PRESENCE(aVP_Header.attributeType = 31)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,challengeValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ProxyAuthenIdAVP + { + AVP_Header aVP_Header, // type 32 + INT2_BO_LAST idValue + } with { + variant "PRESENCE(aVP_Header.attributeType = 32)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,idValue)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ProxyAuthenResponseAVP + { + AVP_Header aVP_Header, // type 33 + octetstring response + } with { + variant "PRESENCE(aVP_Header.attributeType = 33)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,response)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record CallErrorsAVP + { + AVP_Header aVP_Header, // type 34 + OCT2 reserved, // 0 + OCT4 cRCErrors, + OCT4 framingErrors, + OCT4 hardwareOverruns, + OCT4 bufferOverruns, + OCT4 timeoutErrors, + OCT4 alignmentErrors + } with { + variant "PRESENCE(aVP_Header.attributeType = 34)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,reserved,cRCErrors,framingErrors, + hardwareOverruns,bufferOverruns,timeoutErrors,alignmentErrors)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + type record ACCM_AVP + { + AVP_Header aVP_Header, // type 35 + OCT2 reserved, + OCT4 sendACCM, + OCT4 receiveACCM + } with { + variant "PRESENCE(aVP_Header.attributeType = 35)"; + variant (aVP_Header) "LENGTHTO(aVP_Header,reserved,sendACCM,receiveACCM)"; + variant (aVP_Header) "LENGTHINDEX(lengthValue)"; + } + + + // ============================ + type set of SCCRQ_AVP SCCRQ_AVPs; + + type union SCCRQ_AVP + { + ProtocolVersionAVP protocolVersion, + HostNameAVP hostName, + FramingCapabilitiesAVP framingCapabilities, + AssignedTunnelIdAVP assignedTunnelId, + BearerCapabilitiesAVP bearerCapabilities, //optional, + ReceiveWindowSizeAVP receiveWindowSize, //optional, + ChallengeAVP challenge, //optional, + TieBreakerAVP tieBreaker, //optional, + FirmwareRevisionAVP firmwareRevision, //optional, + VendorNameAVP vendorName, //optional + RandomVectorAVP randomVectorAVP //optional + } + + type set of SCCRP_AVP SCCRP_AVPs; + + type union SCCRP_AVP + { + ProtocolVersionAVP protocolVersion, + FramingCapabilitiesAVP framingCapabilities, + HostNameAVP hostName, + AssignedTunnelIdAVP assignedTunnelId, + BearerCapabilitiesAVP bearerCapabilities, //optional, + FirmwareRevisionAVP firmwareRevision, //optional, + VendorNameAVP vendorName, //optional, + ReceiveWindowSizeAVP receiveWindowSize, //optional, + ChallengeAVP challenge, //optional, + ChallengeResponseAVP challengeResponse, //optional + RandomVectorAVP randomVectorAVP //optional + } + + type set of SCCCN_AVP SCCCN_AVPs; + + type union SCCCN_AVP + { + ChallengeResponseAVP challengeResponse, //optional + RandomVectorAVP randomVectorAVP //optional + } + + type set of StopCCN_AVP StopCCN_AVPs; + + type union StopCCN_AVP + { + AssignedTunnelIdAVP assignedTunnelId, + ResultCodeAVP resultCode, + RandomVectorAVP randomVectorAVP //optional + } + + // type set HELLO_AVPs + // { + // } + + type set of OCRQ_AVP OCRQ_AVPs; + + type union OCRQ_AVP + { + AssignedSessionIdAVP assignedSessionId, + CallSerialNumberAVP callSerialNumber, + MinimumBPSAVP minimumBPS, + MaximumBPSAVP maximumBPS, + BearerTypeAVP bearerType, + FramingTypeAVP framingType, + CalledNumberAVP calledNumber, + SUB_AddressAVP sUB_Address, //optional + RandomVectorAVP randomVector //optional + } + + type set of OCRP_AVP OCRP_AVPs; + + type union OCRP_AVP + { + AssignedSessionIdAVP assignedSessionId, + PhysicalChannelIdAVP physicalChannelId, //optional + RandomVectorAVP randomVector //optional + } + + type set of OCCN_AVP OCCN_AVPs; + + type union OCCN_AVP + { + TxConnectSpeedAVP txConnectSpeed, + FramingTypeAVP framingType, + RxConnectSpeedAVP rxConnectSpeed, //optional, + SequencingRequiredAVP sequencingRequired, //optional + RandomVectorAVP randomVector //optional + } + + + type set of ICRQ_AVP ICRQ_AVPs; + + type union ICRQ_AVP + { + AssignedSessionIdAVP assignedSessionId, + CallSerialNumberAVP callSerialNumber, + BearerTypeAVP bearerType, //optional, + PhysicalChannelIdAVP physicalChannelId, //optional, + CallingNumberAVP callingNumber, //optional, + CalledNumberAVP calledNumber, //optional, + SUB_AddressAVP sUB_Address, //optional + RandomVectorAVP randomVector //optional + } + + + type set of ICRP_AVP ICRP_AVPs; + + type union ICRP_AVP + { + AssignedSessionIdAVP assignedSessionId, + RandomVectorAVP randomVector + } + + type set of ICCN_AVP ICCN_AVPs; + + type union ICCN_AVP + { + TxConnectSpeedAVP txConnectSpeed, + FramingTypeAVP framingType, + InitialReceivedLCP_CONFREQ_AVP initialReceivedLCP_CONFREQ_AVP, + LastSentLCP_CONFREQ_AVP lastSentLCP_CONFREQ_AVP, //optional, + LastReceivedLCP_CONFREQ_AVP lastReceivedLCP_CONFREQ_AVP, //optional, + ProxyAuthenTypeAVP proxyAuthenType, //optional, + ProxyAuthenNameAVP proxyAuthenName, //optional, + ProxyAuthenChallengeAVP proxyAuthenChallenge, //optional, + ProxyAuthenIdAVP proxyAuthenId, //optional, + ProxyAuthenResponseAVP proxyAuthenResponse, //optional, + PrivateGroupIdAVP privateGroupId, //optional, + RxConnectSpeedAVP rxConnectSpeed, //optional, + SequencingRequiredAVP sequencingRequired, //optional + RandomVectorAVP randomVector //optional + } + + type set of CDN_AVP CDN_AVPs; + + type union CDN_AVP + { + ResultCodeAVP resultCode, + AssignedSessionIdAVP assignedSessionId, + Q931CauseCodeAVP q931CauseCode, //optional + RandomVectorAVP randomVector //optional + } + + type set of WEN_AVP WEN_AVPs; + + type union WEN_AVP + { + CallErrorsAVP callErrors, + RandomVectorAVP randomVector //optional + } + + type set of SLI_AVP SLI_AVPs; + + type union SLI_AVP + { + ACCM_AVP aCCM, + RandomVectorAVP randomVector //optional + } + + + // Control Messages ============================ + + + type record SCCRQ + { + MessageTypeAVP messageType, + SCCRQ_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 1)"; }; + + type record SCCRP + { + MessageTypeAVP messageType, + SCCRP_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 2)"; }; + + + type record SCCCN + { + MessageTypeAVP messageType, + SCCCN_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 3)"; }; + + + type record StopCCN + { + MessageTypeAVP messageType, + StopCCN_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 4)"; }; + + + type record HELLO + { + MessageTypeAVP messageType + // HELLO_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 6)"; }; + + + type record OCRQ + { + MessageTypeAVP messageType, + OCRQ_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 7)"; }; + + + type record OCRP + { + MessageTypeAVP messageType, + OCRP_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 8)"; }; + + + type record OCCN + { + MessageTypeAVP messageType, + OCCN_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 9)"; }; + + + type record ICRQ + { + MessageTypeAVP messageType, + ICRQ_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 10)"; }; + + + type record ICRP + { + MessageTypeAVP messageType, + ICRP_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 11)"; }; + + + type record ICCN + { + MessageTypeAVP messageType, + ICCN_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 12)"; }; + + + type record CDN + { + MessageTypeAVP messageType, + CDN_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 14)"; }; + + + type record WEN + { + MessageTypeAVP messageType, + WEN_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 15)"; }; + + + type record SLI + { + MessageTypeAVP messageType, + SLI_AVPs aVPs + } with { variant "PRESENCE (messageType.messageTypeValue = 16)"; }; + + type record ZLB + { + } + + // L2TP Header ============================ + + type record L2TP_Offset + { + INT2_BO_LAST offsetSize, + octetstring offsetPad optional + } with { variant (offsetSize) "LENGTHTO(offsetPad)";} + + + type record L2TP_Header + { + BIT1 pBit, //pBit (priority), 0 in ctrl messages + BIT1 oBit, //if oBit is 1 offset field is present, 0 in ctrl messages + BIT1 reserved, //'0'B + BIT1 sBit, //if sBit is 1 ns and nr fields are present, 1 in ctrl messages + BIT2 reserved2, //'0'B + BIT1 lBit, //if lBit is 1 lengthValuefield is present, 1 in ctrl messages + BIT1 tBit, // type of message (0=dataMessage, 1=controlMessage) + BIT4 ver, //'0010'B + BIT4 reserved3, //'0'B + INT2_BO_LAST lengthValue optional, + INT2_BO_LAST tunnelId, + INT2_BO_LAST sessionId, + INT2_BO_LAST ns optional, + INT2_BO_LAST nr optional, + L2TP_Offset offset optional + } with { + variant (lengthValue) "PRESENCE(lBit = '1'B)"; + variant (ns) "PRESENCE(sBit = '1'B)"; + variant (nr) "PRESENCE(sBit = '1'B)"; + variant (offset) "PRESENCE(oBit = '1'B)"; + } + + // L2TP PDU ============================ + + type union ControlMessage + { + SCCRQ sCCRQ, + SCCRP sCCRP, + SCCCN sCCCN, + StopCCN stopCCN, + HELLO hELLO, + OCRQ oCRQ, + OCRP oCRP, + OCCN oCCN, + ICRQ iCRQ, + ICRP iCRP, + ICCN iCCN, + CDN cDN, + WEN wEN, + SLI sLI, + ZLB zLB + } + + type union L2TP_Body + { + octetstring dataMessage, + ControlMessage controlMessage + } + + type record PDU_L2TP + { + L2TP_Header header, + L2TP_Body body + } with { + variant (body)"CROSSTAG(dataMessage, header.tBit = '0'B; + controlMessage, header.tBit = '1'B)" + } + +} with { encode "RAW"} // end of module