Review at  https://gerrit.osmocom.org/6567

ggsn: Move GTP templates to separate GTP_Templates + Add GTP_Emulation

Change-Id: I384e59738a9e0fc0186b69f0806f217a2a8d8a4b
---
M ggsn_tests/GGSN_Tests.ttcn
M ggsn_tests/gen_links.sh
A library/GTP_Emulation.ttcn
A library/GTP_Templates.ttcn
4 files changed, 777 insertions(+), 510 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks 
refs/changes/67/6567/1

diff --git a/ggsn_tests/GGSN_Tests.ttcn b/ggsn_tests/GGSN_Tests.ttcn
index 28f461c..f320c20 100644
--- a/ggsn_tests/GGSN_Tests.ttcn
+++ b/ggsn_tests/GGSN_Tests.ttcn
@@ -6,6 +6,7 @@
        import from IPL4asp_Types all;
        import from GTP_CodecPort all;
        import from GTP_CodecPort_CtrlFunct all;
+       import from GTP_Templates all;
        import from GTPC_Types all;
        import from GTPU_Types all;
        import from IPCP_Types all;
@@ -93,515 +94,6 @@
                g_restart_ctr := f_rnd_octstring(1);
                g_c_seq_nr := f_rnd_int(65535);
                g_d_seq_nr := f_rnd_int(65535);
-       }
-
-       /* generalized GTP-C receive template */
-       template PDU_GTPC tr_GTP1C_PDU(template OCT1 msg_type, template OCT4 
teid, template GTPC_PDUs pdu := ?) := {
-               /* N-PDU Number flag (PN) shall be set to '0'. A GTP-C receiver 
shall not return an
-                * error if this flag is set to '1'. */
-               pn_bit := '0'B,
-               /* Sequence number flag (S) shall be set to '1'. */
-               s_bit := '1'B,
-               e_bit := ?,
-               spare := ?,
-               /* Protocol Type flag (PT) shall be set to '1'.*/
-               pt := '1'B,
-               /* Version shall be set to decimal 1 ('001'). */
-               version := '001'B,
-               messageType := msg_type,
-               lengthf := ?,
-               teid := teid,
-               opt_part := *,
-               gtpc_pdu := pdu
-       }
-
-       /* generalized GTP-C send template */
-       template PDU_GTPC ts_GTP1C_PDU(OCT1 msg_type, OCT4 teid, GTPC_PDUs pdu, 
uint16_t seq_nr) := {
-               /* N-PDU Number flag (PN) shall be set to '0'. A GTP-C receiver 
shall not return an
-                * error if this flag is set to '1'. */
-               pn_bit := '0'B,
-               /* Sequence number flag (S) shall be set to '1'. */
-               s_bit := '1'B,
-               e_bit := '0'B,
-               spare := '0'B,
-               /* Protocol Type flag (PT) shall be set to '1'.*/
-               pt := '1'B,
-               /* Version shall be set to decimal 1 ('001'). */
-               version := '001'B,
-               messageType := msg_type,
-               lengthf := 0,   /* we assume encoder overwrites this */
-               teid := teid,
-               opt_part := {
-                       sequenceNumber := int2oct(seq_nr, 2),
-                       npduNumber := '00'O,
-                       nextExtHeader := '00'O,
-                       gTPC_extensionHeader_List := omit
-               },
-               gtpc_pdu := pdu
-       }
-
-       /* recovery IE */
-       template Recovery_gtpc ts_Recovery(OCT1 restart_counter) := {
-               type_gtpc := '0E'O,
-               restartCounter := restart_counter
-       }
-
-       template Recovery_gtpc tr_Recovery(template OCT1 restart_counter) := {
-               type_gtpc := '0E'O,
-               restartCounter := restart_counter
-       }
-
-       /* template matching reception of GTP-C echo-request */
-       template Gtp1cUnitdata tr_GTPC_MsgType(template GtpPeer peer, template 
OCT1 msg_type, template OCT4 teid, template GTPC_PDUs pdus := ?) := {
-               peer := peer,
-               gtpc := tr_GTP1C_PDU(msg_type, teid, pdus)
-       }
-
-       /* template matching reception of GTP-C echo-request */
-       template Gtp1cUnitdata tr_GTPC_PING(template GtpPeer peer) := 
tr_GTPC_MsgType(peer, echoRequest, '00000000'O);
-
-       template GTPC_PDUs tr_EchoRespPDU(template OCT1 restart_counter) := {
-               echoResponse := {
-                       recovery := tr_Recovery(restart_counter),
-                       private_extension_gtpc := *
-               }
-       }
-
-       /* template matching reception of GTP-C echo-response */
-       template Gtp1cUnitdata tr_GTPC_PONG(template GtpPeer peer) := 
tr_GTPC_MsgType(peer, echoResponse, '00000000'O, tr_EchoRespPDU(?));
-
-       template GTPC_PDUs ts_EchoRespPDU(OCT1 restart_counter) := {
-               echoResponse := {
-                       recovery := ts_Recovery(restart_counter),
-                       private_extension_gtpc := omit
-               }
-       }
-
-       /* master template for senidng a GTP-C echo response */
-       template Gtp1cUnitdata ts_GTPC_PONG(GtpPeer peer, uint16_t seq, OCT1 
rest_ctr) := {
-               peer := peer,
-               gtpc := ts_GTP1C_PDU(echoResponse, '00000000'O, 
valueof(ts_EchoRespPDU(rest_ctr)), seq)
-       }
-
-       template GTPC_PDUs ts_EchoReqPDU := {
-               echoRequest := {
-                       private_extension_gtpc := omit
-               }
-       }
-
-       /* master template for sending a GTP-C echo request */
-       template Gtp1cUnitdata ts_GTPC_PING(GtpPeer peer, uint16_t seq) := {
-               peer := peer,
-               gtpc := ts_GTP1C_PDU(echoRequest, '00000000'O, 
valueof(ts_EchoReqPDU), seq)
-       }
-
-       template EndUserAddress t_EuaIPv4(template OCT4 ip_addr) := {
-               type_gtpc := '80'O,
-               endUserAddress := {
-                       endUserAddressIPv4 := {
-                               lengthf := 2,
-                               pdp_typeorg := '0001'B,
-                               spare := '1111'B,
-                               pdp_typenum := '21'O,
-                               ipv4_address := ip_addr
-                       }
-               }
-       }
-       template EndUserAddress t_EuaIPv4Dyn := t_EuaIPv4(omit);
-       template EndUserAddress tr_EuaIPv4(template OCT4 ip_addr) modifies 
t_EuaIPv4 := {
-               endUserAddress := {
-                       endUserAddressIPv4 := {
-                               lengthf := 2+lengthof(ip_addr)
-                       }
-               }
-       }
-
-       template EndUserAddress t_EuaIPv6(template OCT16 ip_addr) := {
-               type_gtpc := '80'O,
-               endUserAddress := {
-                       endUserAddressIPv6 := {
-                               lengthf := 2,
-                               pdp_typeorg := '0001'B,
-                               spare := '1111'B,
-                               pdp_typenum := '57'O,
-                               ipv6_address := ip_addr
-                       }
-               }
-       }
-       template EndUserAddress t_EuaIPv6Dyn := t_EuaIPv6(omit);
-       template EndUserAddress tr_EuaIPv6(template OCT16 ip_addr) modifies 
t_EuaIPv6 := {
-               endUserAddress := {
-                       endUserAddressIPv6 := {
-                               lengthf := 2+lengthof(ip_addr)
-                       }
-               }
-       }
-
-       template AccessPointName ts_APN(octetstring apn) := {
-               type_gtpc := '83'O,
-               lengthf := lengthof(apn),
-               apn_value := apn
-       }
-
-       template GSN_Address_GTPC ts_GsnAddr(octetstring ip_addr) := {
-               type_gtpc := '85'O,
-               lengthf := lengthof(ip_addr),
-               addressf := ip_addr
-       }
-
-       template MSISDN ts_Msisdn(octetstring msisdn) := {
-               type_gtpc := '86'O,
-               lengthf := lengthof(msisdn),
-               msisdn := msisdn
-       }
-
-       template QualityOfServiceProfile ts_QosDefault := {
-               type_gtpc := '87'O,
-               lengthf := 4,
-               allocRetensionPrio := '00'O,
-               qos_ProfileValue := {
-                       reliabilityClass := '011'B,
-                       delayClass := '001'B,
-                       spare1 := '00'B,
-                       precedenceClass := '010'B,
-                       spare2 := '0'B,
-                       peakThroughput := '1001'B,
-                       meanThroughput := '11111'B,
-                       spare3 := '000'B,
-                       deliverErroneusSDU := omit,
-                       deliveryOrder := omit,
-                       trafficClass := omit,
-                       maxSDUSize := omit,
-                       maxBitrateUplink := omit,
-                       maxBitrateDownlink := omit,
-                       sduErrorRatio := omit,
-                       residualBER := omit,
-                       trafficHandlingPriority := omit,
-                       transferDelay := omit,
-                       guaranteedBitRateUplink := omit,
-                       guaranteedBitRateDownlink := omit,
-                       sourceStatisticsDescriptor := omit,
-                       signallingIndication := omit,
-                       spare4 := omit,
-                       maxBitrateDownlinkExt := omit,
-                       guaranteedBitRateDownlinkExt := omit,
-                       maxBitrateUplinkExt := omit,
-                       guaranteedBitRateUplinkExt := omit
-               }
-       }
-
-       template IMSI_gtpc ts_Imsi(hexstring digits) := {
-               type_gtpc := '02'O,
-               digits := digits,
-               padding := 'F'H
-       }
-
-       template GTPC_PDUs ts_CreatePdpPDU(hexstring imsi, OCT1 restart_ctr, 
OCT4 teid_data, OCT4 teid_ctrl,
-                                          BIT4 nsapi, EndUserAddress eua, 
octetstring apn,
-                                          octetstring sgsn_ip_sign, 
octetstring sgsn_ip_data,
-                                          octetstring msisdn, template 
ProtConfigOptions pco := omit) := {
-               createPDPContextRequest := {
-                       imsi := ts_Imsi(imsi),
-                       rai := omit,
-                       recovery := ts_Recovery(restart_ctr),
-                       selectionMode := {
-                               type_gtpc := '0F'O,
-                               selectModeValue := '00'B,
-                               spare := '111111'B
-                       },
-                       teidDataI := {
-                               type_gtpc := '00'O,
-                               teidDataI := teid_data
-                       },
-                       teidControlPlane := {
-                               type_gtpc := '00'O,
-                               teidControlPlane := teid_ctrl
-                       },
-                       nsapi := {
-                               type_gtpc := '00'O,
-                               nsapi := nsapi,
-                               unused := '0000'B
-                       },
-                       linked_nsapi := omit,
-                       charging_char := omit,
-                       trace_ref := omit,
-                       trace_type := omit,
-                       endUserAddress := eua,
-                       accessPointName := ts_APN(apn),
-                       protConfigOptions := pco,
-                       sgsn_addr_signalling := ts_GsnAddr(sgsn_ip_sign),
-                       sgsn_addr_traffic := ts_GsnAddr(sgsn_ip_data),
-                       msisdn := ts_Msisdn(msisdn),
-                       qualityOfServiceProfile := ts_QosDefault,
-                       tft := omit,
-                       triggerId := omit,
-                       omcId := omit,
-                       commonFlags := omit,
-                       aPN_Restriction := omit,
-                       ratType := omit,
-                       userLocationInformation := omit,
-                       mS_TimeZone := omit,
-                       imeisv := omit,
-                       camelChargingInformationContainer := omit,
-                       additionalTraceInfo := omit,
-                       correlationID := omit,
-                       evolvedAllocationRetentionPriorityI := omit,
-                       extendedCommonFlags := omit,
-                       userCSGInformation := omit,
-                       aPN_AMBR := omit,
-                       signallingPriorityIndication := omit,
-                       cN_OperatorSelectionEntity := omit,
-                       private_extension_gtpc := omit
-               }
-       }
-
-       template Gtp1cUnitdata ts_GTPC_CreatePDP(GtpPeer peer, uint16_t seq, 
hexstring imsi,
-                                                OCT1 restart_ctr, OCT4 
teid_data,
-                                                OCT4 teid_ctrl, BIT4 nsapi, 
EndUserAddress eua,
-                                                octetstring apn, octetstring 
sgsn_ip_sign,
-                                                octetstring sgsn_ip_data, 
octetstring msisdn,
-                                                template ProtConfigOptions pco 
:= omit) := {
-               peer := peer,
-               gtpc := ts_GTP1C_PDU(createPDPContextRequest, '00000000'O,
-                                       valueof(ts_CreatePdpPDU(imsi, 
restart_ctr, teid_data, teid_ctrl,
-                                                               nsapi, eua, 
apn, sgsn_ip_sign,
-                                                               sgsn_ip_data, 
msisdn, pco)), seq)
-       }
-
-       /* PCO send base template */
-       template ProtConfigOptions ts_PCO := {
-               type_gtpc := '84'O,
-               lengthf := 0,
-               configProtocol := '000'B,
-               spare := '0000'B,
-               extension0 := '1'B,
-               protocols := {}
-       }
-       /* PCO receive base template */
-       template ProtConfigOptions tr_PCO := {
-               type_gtpc := '84'O,
-               lengthf := ?,
-               configProtocol := '000'B,
-               spare := ?,
-               extension0 := '1'B,
-               protocols := {}
-       }
-
-       template ProtConfigOptions ts_PCO_IPv6_DNS modifies ts_PCO := {
-               protocols := {
-                       { protocolID := '0003'O, lengthProtoID := 0, 
protoIDContents := ''O }
-               }
-       }
-       template ProtConfigOptions tr_PCO_IPv6_DNS_resp(template OCT16 
contents) modifies tr_PCO := {
-               protocols := {
-                       *, { protocolID := '0003'O, lengthProtoID := 16, 
protoIDContents := contents }, *
-               }
-       }
-
-       template ProtConfigOptions ts_PCO_IPv4_DNS_IPCP modifies ts_PCO := {
-               protocols := {
-                       /* dummy PAP entry to check if our parser in the GGSN 
can properly iterate over
-                        * the list of protocols, see Change-Id 
Icc2e6716c33d78d3c3e000f529806228d8aa155e */
-                       { protocolID := 'C023'O, lengthProtoID := 0, 
protoIDContents := ''O },
-                       { protocolID := '8021'O, lengthProtoID := 16, 
protoIDContents :=
-                                                               
enc_IpcpPacket(valueof(ts_IPCP_ReqDNS)) }
-               }
-       }
-
-       template ProtocolElement tr_PCO_Proto(OCT2 prot_id) := {
-               protocolID := prot_id,
-               lengthProtoID := ?,
-               protoIDContents := ?
-       }
-       template ProtConfigOptions tr_PCO_Contains(OCT2 prot_id) modifies 
tr_PCO := {
-               protocols := { *, tr_PCO_Proto(prot_id), * }
-       }
-
-       template ProtConfigOptions ts_PCO_IPv4_DNS_CONT modifies ts_PCO := {
-               protocols := {
-                       { protocolID := '000d'O, lengthProtoID := 0, 
protoIDContents := ''O }
-               }
-       }
-       template ProtConfigOptions tr_PCO_IPv4_DNS_CONT_resp(template OCT4 
contents) modifies tr_PCO := {
-               protocols := {
-                       *, { protocolID := '000d'O, lengthProtoID := 4, 
protoIDContents := contents }, *
-               }
-       }
-
-       /* extract a given protocol payload from PCO */
-       function f_PCO_extract_proto(ProtConfigOptions pco, OCT2 protocol, 
integer nth_match := 1) return octetstring {
-               var integer i;
-               var integer num_matches := 0;
-               for (i := 0; i < lengthof(pco.protocols); i := i + 1) {
-                       if (pco.protocols[i].protocolID == protocol) {
-                               num_matches := num_matches + 1;
-                               if (num_matches == nth_match) {
-                                       return pco.protocols[i].protoIDContents;
-                               }
-                       }
-               }
-               setverdict(fail);
-               return ''O;
-       }
-
-       template IpcpPacket tr_IPCP(template LcpCode code, template uint8_t 
identifier,
-                                   template IpcpOptionList opts) := {
-               code := code,
-               identifier := identifier,
-               len := ?,
-               options := opts
-       }
-       template IpcpOption tr_IPCP_PrimaryDns(template OCT4 addr) := {
-               code := IPCP_OPT_PrimaryDNS,
-               len := 6,
-               data := addr
-       }
-       template IpcpOption tr_IPCP_SecondaryDns(template OCT4 addr) := {
-               code := IPCP_OPT_SecondaryDNS,
-               len := 6,
-               data := addr
-       }
-       template IpcpPacket tr_IPCP_Ack_DNS(template uint8_t identifier := ?, 
template OCT4 dns1 := ?,
-                                           template OCT4 dns2 := ?) :=
-               tr_IPCP(LCP_Configure_Ack, identifier,
-                               { *, tr_IPCP_PrimaryDns(dns1), *, 
tr_IPCP_SecondaryDns(dns2), * });
-
-       template IpcpPacket ts_IPCP(LcpCode code, uint8_t identifier, template 
IpcpOptionList opts) := {
-               code := code,
-               identifier := identifier,
-               len := 0,       /* overwritten */
-               options := opts
-       }
-       template IpcpPacket ts_IPCP_ReqDNS(uint8_t identifier := 0) :=
-               ts_IPCP(LCP_Configure_Request, identifier,
-                       { tr_IPCP_PrimaryDns('00000000'O), 
tr_IPCP_SecondaryDns('00000000'O) });
-
-       function f_teardown_ind_IE(in template BIT1 ind) return template 
TearDownInd {
-/*
-               if (not isvalue(ind)) {
-                       return omit;
-               }
-*/
-               var TearDownInd ret := {
-                       type_gtpc := '13'O,
-                       tdInd := valueof(ind),
-                       spare:= '0000000'B
-               }
-               return ret;
-       }
-
-       template GTPC_PDUs ts_DeletePdpPDU(BIT4 nsapi, template BIT1 
teardown_ind) := {
-               deletePDPContextRequest := {
-                       cause := omit,
-                       tearDownIndicator := f_teardown_ind_IE(teardown_ind),
-                       nsapi := {
-                               type_gtpc := '14'O,
-                               nsapi := nsapi,
-                               unused := '0000'B
-                       },
-                       protConfigOptions := omit,
-                       userLocationInformation := omit,
-                       mS_TimeZone := omit,
-                       extendedCommonFlags := omit,
-                       uLI_Timestamp := omit,
-                       private_extension_gtpc := omit
-               }
-       }
-
-       template Gtp1cUnitdata ts_GTPC_DeletePDP(GtpPeer peer, uint16_t seq, 
OCT4 teid,
-                                                BIT4 nsapi, template BIT1 
teardown_ind) := {
-               peer := peer,
-               gtpc := ts_GTP1C_PDU(deletePDPContextRequest, teid,
-                                       valueof(ts_DeletePdpPDU(nsapi, 
teardown_ind)), seq)
-       }
-
-
-       /* GTP-U */
-
-       template PDU_GTPU tr_GTP1U_PDU(template OCT1 msg_type, template OCT4 
teid, template GTPU_IEs ies := ?) := {
-               pn_bit := ?,
-               s_bit := ?,
-               e_bit := ?,
-               spare := ?,
-               /* Protocol Type flag (PT) shall be set to '1' in GTP */
-               pt := '1'B,
-               /* Version shall be set to decimal 1 ('001'). */
-               version := '001'B,
-               messageType := msg_type,
-               lengthf := ?,
-               teid := teid,
-               opt_part := *,
-               gtpu_IEs := ies
-       }
-
-       /* generalized GTP-U send template */
-       template PDU_GTPU ts_GTP1U_PDU(OCT1 msg_type, uint16_t seq, OCT4 teid, 
GTPU_IEs ies) := {
-               /* N-PDU Number flag (PN): the GTP-U header contains a 
meaningful N-PDU Number field if the PN
-                * flag is set to 1. */
-               pn_bit := '0'B, /* we assume the encoder overwrites this if an 
optional part is given */
-               /* If the Sequence Number flag (S) is set to '1' the sequence 
number field is present and
-                * meaningful otherwise it is set to '0'. For GTP-U messages 
Echo Request, Echo Response,
-                * Error Indication and Supported Extension Headers 
Notification, the S flag shall be set to '1'. */
-               s_bit := '1'B,  /* we assume the encoder overwrites this if an 
optional part is given */
-               /* Extension header presence */
-               e_bit := '0'B,
-               spare := '0'B,
-               /* Protocol Type flag (PT) shall be set to '1' in GTP */
-               pt := '1'B,
-               /* Version shall be set to decimal 1 ('001'). */
-               version := '001'B,
-               messageType := msg_type,
-               lengthf := 0,   /* we assume encoder overwrites this */
-               teid := teid,
-               opt_part :=  {
-                       sequenceNumber := int2oct(seq, 2),
-                       npduNumber := '00'O,
-                       nextExtHeader := '00'O,
-                       gTPU_extensionHeader_List := omit
-               },
-               gtpu_IEs := ies
-       }
-
-       template Gtp1uUnitdata tr_GTPU_MsgType(template GtpPeer peer, template 
OCT1 msg_type, template OCT4 teid) := {
-               peer := peer,
-               gtpu := tr_GTP1U_PDU(msg_type, teid)
-       }
-
-
-       /* template matching reception of GTP-U echo-request */
-       template Gtp1uUnitdata tr_GTPU_PING(template GtpPeer peer) := 
tr_GTPU_MsgType(peer, echoRequest, '00000000'O);
-
-       /* template matching reception of GTP-U GPDU */
-       template GTPU_IEs t_GPDU(template octetstring data) := {
-               g_PDU_IEs := {
-                       data := data
-               }
-       }
-       template Gtp1uUnitdata tr_GTPU_GPDU(template GtpPeer peer, template 
OCT4 teid, template octetstring data := ?) := {
-               peer := peer,
-               gtpu := tr_GTP1U_PDU('FF'O, teid, t_GPDU(data))
-       }
-
-       template GTPU_IEs ts_UEchoRespPDU(OCT1 restart_counter) := {
-               echoResponse_IEs := {
-                       recovery_gtpu := {
-                               type_gtpu := '00'O, /* we assume encoder fixes? 
*/
-                               restartCounter := restart_counter
-                       },
-                       private_extension_gtpu := omit
-               }
-       }
-
-       /* master template for sending a GTP-U echo response */
-       template Gtp1uUnitdata ts_GTPU_PONG(GtpPeer peer, uint16_t seq, OCT1 
rest_ctr) := {
-               peer := peer,
-               gtpu := ts_GTP1U_PDU(echoResponse, seq, '00000000'O, 
valueof(ts_UEchoRespPDU(rest_ctr)))
-       }
-
-       /* master template for sending a GTP-U user plane data */
-       template Gtp1uUnitdata ts_GTP1U_GPDU(GtpPeer peer, uint16_t seq, OCT4 
teid, octetstring data) := {
-               peer := peer,
-               gtpu := ts_GTP1U_PDU('FF'O, seq, teid, { g_PDU_IEs := { data := 
data }})
        }
 
        /* Altstep implementing responses to any incoming echo requests */
diff --git a/ggsn_tests/gen_links.sh b/ggsn_tests/gen_links.sh
index c04d19e..071c6c8 100755
--- a/ggsn_tests/gen_links.sh
+++ b/ggsn_tests/gen_links.sh
@@ -49,5 +49,5 @@
 
 DIR=../library
 FILES="General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn 
Native_Functions.ttcn Native_FunctionDefs.cc IPCP_Types.ttcn "
-FILES+="GTP_CodecPort.ttcn GTP_CodecPort_CtrlFunct.ttcn 
GTP_CodecPort_CtrlFunctDef.cc "
+FILES+="GTP_CodecPort.ttcn GTP_CodecPort_CtrlFunct.ttcn 
GTP_CodecPort_CtrlFunctDef.cc GTP_Templates.ttcn "
 gen_links $DIR $FILES
diff --git a/library/GTP_Emulation.ttcn b/library/GTP_Emulation.ttcn
new file mode 100644
index 0000000..e5e5e36
--- /dev/null
+++ b/library/GTP_Emulation.ttcn
@@ -0,0 +1,257 @@
+module GTP_Emulation {
+
+import from IPL4asp_Types all;
+import from General_Types all;
+import from Osmocom_Types all;
+import from GTPC_Types all;
+import from GTPU_Types all;
+import from GTP_CodecPort all;
+import from GTP_CodecPort_CtrlFunct all;
+
+/***********************************************************************
+ * Main Emulation Component
+ ***********************************************************************/
+
+const integer GTP0_PORT := 3386;
+const integer GTP1C_PORT := 2123;
+const integer GTP1U_PORT := 2152;
+
+type record GtpEmulationCfg {
+       HostName gtpc_bind_ip,
+       PortNumber gtpc_bind_port,
+       HostName gtpu_bind_ip,
+       PortNumber gtpu_bind_port,
+       boolean sgsn_role
+};
+
+type component GTP_Emulation_CT {
+       /* Communication with underlying GTP CodecPort */
+       port GTPC_PT GTPC;
+       port GTPU_PT GTPU;
+
+       /* Communication with Clients */
+       port GTPEM_PT CLIENT;
+       port GTPEM_PROC_PT CLIENT_PROC;
+
+       /* Configuration by the user */
+       var GtpEmulationCfg g_gtp_cfg;
+
+       /* State */
+       var integer g_gtpc_id, g_gtpu_id;
+       var OCT1 g_restart_ctr;
+       var uint16_t g_c_seq_nr, g_u_seq_nr;
+       var TidTableRec TidTable[16];
+       var ImsiTableRec ImsiTable[16];
+};
+
+type record TidTableRec {
+       OCT4 teid,
+       GTP_ConnHdlr vc_conn
+};
+
+type record ImsiTableRec {
+       hexstring imsi,
+       GTP_ConnHdlr vc_conn
+};
+
+private function f_comp_by_teid(OCT4 teid) runs on GTP_Emulation_CT return 
GTP_ConnHdlr {
+       var integer i;
+       for (i := 0; i < sizeof(TidTable); i := i+1) {
+               if (isbound(TidTable[i].teid) and TidTable[i].teid == teid) {
+                       return TidTable[i].vc_conn;
+               }
+       }
+       setverdict(fail, "No Component for TEID ", teid);
+       self.stop;
+}
+
+private function f_comp_by_imsi(hexstring imsi) runs on GTP_Emulation_CT 
return GTP_ConnHdlr {
+       var integer i;
+       for (i := 0; i < sizeof(ImsiTable); i := i+1) {
+               if (isbound(ImsiTable[i].imsi) and ImsiTable[i].imsi == imsi) {
+                       return ImsiTable[i].vc_conn;
+               }
+       }
+       setverdict(fail, "No Component for IMSI ", imsi);
+       self.stop;
+}
+
+private function f_tid_tbl_add(OCT4 teid, GTP_ConnHdlr vc_conn) runs on 
GTP_Emulation_CT {
+       var integer i;
+       for (i := 0; i < sizeof(TidTable); i := i+1) {
+               if (not isbound(TidTable[i].teid)) {
+                       TidTable[i].teid := teid;
+                       TidTable[i].vc_conn := vc_conn;
+                       return;
+               }
+       }
+       setverdict(fail, "No Space in TidTable for ", teid);
+       self.stop;
+}
+
+private function f_imsi_tbl_add(hexstring imsi, GTP_ConnHdlr vc_conn) runs on 
GTP_Emulation_CT {
+       var integer i;
+       for (i := 0; i < sizeof(ImsiTable); i := i+1) {
+               if (not isbound(ImsiTable[i].imsi)) {
+                       ImsiTable[i].imsi := imsi;
+                       ImsiTable[i].vc_conn := vc_conn;
+                       return;
+               }
+       }
+       setverdict(fail, "No Space in IMSI Table for ", imsi);
+       self.stop;
+}
+
+function f_gtpc_extract_imsi(PDU_GTPC gtp) return template (omit) hexstring {
+       if (ischosen(gtp.gtpc_pdu.createPDPContextRequest)) {
+               return gtp.gtpc_pdu.createPDPContextRequest.imsi.digits;
+       } else if 
(ischosen(gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestSGSN)) {
+               return 
gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestSGSN.imsi.digits;
+       } else if 
(ischosen(gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestGGSN)) {
+               return 
gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestGGSN.imsi.digits;
+       } else if 
(ischosen(gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestCGW)) {
+               return 
gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestCGW.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.pdu_NotificationRequest)) {
+               return gtp.gtpc_pdu.pdu_NotificationRequest.imsi.digits;
+       } else if 
(ischosen(gtp.gtpc_pdu.sendRouteingInformationForGPRSRequest)) {
+               return 
gtp.gtpc_pdu.sendRouteingInformationForGPRSRequest.imsi.digits;
+       } else if 
(ischosen(gtp.gtpc_pdu.sendRouteingInformationForGPRSResponse)) {
+               return 
gtp.gtpc_pdu.sendRouteingInformationForGPRSResponse.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.failureReportRequest)) {
+               return gtp.gtpc_pdu.failureReportRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.noteMS_GPRSPresentRequest)) {
+               return gtp.gtpc_pdu.noteMS_GPRSPresentRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.identificationResponse) ){
+               return gtp.gtpc_pdu.identificationResponse.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.sgsn_ContextRequest)) {
+               return gtp.gtpc_pdu.sgsn_ContextRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.sgsn_ContextResponse)) {
+               return gtp.gtpc_pdu.sgsn_ContextResponse.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.forwardRelocationRequest)) {
+               return gtp.gtpc_pdu.forwardRelocationRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.relocationCancelRequest)) {
+               return gtp.gtpc_pdu.relocationCancelRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.uERegistrationQueryRequest)) {
+               return gtp.gtpc_pdu.uERegistrationQueryRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.uERegistrationQueryResponse)) {
+               return gtp.gtpc_pdu.uERegistrationQueryResponse.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.mBMSNotificationRequest)) {
+               return gtp.gtpc_pdu.mBMSNotificationRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.createMBMSContextRequest)) {
+               return gtp.gtpc_pdu.createMBMSContextRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.deleteMBMSContextRequest)) {
+               return gtp.gtpc_pdu.deleteMBMSContextRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.mS_InfoChangeNotificationRequest)) {
+               return 
gtp.gtpc_pdu.mS_InfoChangeNotificationRequest.imsi.digits;
+       } else if (ischosen(gtp.gtpc_pdu.mS_InfoChangeNotificationResponse)) {
+               return 
gtp.gtpc_pdu.mS_InfoChangeNotificationResponse.imsi.digits;
+       } else {
+               return omit;
+       }
+}
+
+private function f_init(GtpEmulationCfg cfg) runs on GTP_Emulation_CT {
+       var Result res;
+
+       map(self:GTPC, system:GTPC);
+       res := GTP_CodecPort_CtrlFunct.f_IPL4_listen(GTPC, cfg.gtpc_bind_ip,
+                                                    cfg.gtpc_bind_port, 
{udp:={}});
+       g_gtpc_id := res.connId;
+
+       map(self:GTPU, system:GTPU);
+       res := GTP_CodecPort_CtrlFunct.f_GTPU_listen(GTPU, cfg.gtpu_bind_ip,
+                                                    cfg.gtpu_bind_port, 
{udp:={}});
+       g_gtpu_id := res.connId;
+
+       g_restart_ctr := f_rnd_octstring(1);
+       g_c_seq_nr := f_rnd_int(65535);
+       g_u_seq_nr := f_rnd_int(65535);
+       g_gtp_cfg := cfg;
+}
+
+function main(GtpEmulationCfg cfg) runs on GTP_Emulation_CT {
+       var Gtp1cUnitdata g1c_ud;
+       var Gtp1uUnitdata g1u_ud;
+       var GTP_ConnHdlr vc_conn;
+       var hexstring imsi;
+       var OCT4 teid;
+
+       f_init(cfg);
+
+       while (true) {
+       alt {
+       /* route inbound GTP-C based on IMSI or TEID */
+       [] GTPC.receive(Gtp1cUnitdata:?) -> value g1c_ud {
+               var template hexstring imsi_t := 
f_gtpc_extract_imsi(g1c_ud.gtpc);
+               if (isvalue(imsi_t)) {
+                       vc_conn := f_comp_by_imsi(valueof(imsi_t));
+               } else {
+                       vc_conn := f_comp_by_teid(g1c_ud.gtpc.teid);
+               }
+               CLIENT.send(g1c_ud) to vc_conn;
+               }
+       [] GTPU.receive(Gtp1uUnitdata:?) -> value g1u_ud {
+               vc_conn := f_comp_by_teid(g1u_ud.gtpu.teid);
+               CLIENT.send(g1u_ud) to vc_conn;
+               }
+
+       /* transparently forward any GTP-C / GTP-U from clients to peer[s] */
+       [] CLIENT.receive(Gtp1cUnitdata:?) -> value g1c_ud sender vc_conn {
+               GTPC.send(g1c_ud);
+               }
+       [] CLIENT.receive(Gtp1uUnitdata:?) -> value g1u_ud sender vc_conn {
+               GTPU.send(g1u_ud);
+               }
+
+
+       [] CLIENT_PROC.getcall(GTPEM_register_imsi:{?}) -> param(imsi) sender 
vc_conn {
+               f_imsi_tbl_add(imsi, vc_conn);
+               CLIENT_PROC.reply(GTPEM_register_imsi:{imsi});
+               }
+
+       [] CLIENT_PROC.getcall(GTPEM_register_teid:{?}) -> param(teid) sender 
vc_conn {
+               f_tid_tbl_add(teid, vc_conn);
+               CLIENT_PROC.reply(GTPEM_register_teid:{teid});
+               }
+
+       }
+       }
+}
+
+
+/***********************************************************************
+ * Interaction between Main and Client Components
+ ***********************************************************************/
+type port GTPEM_PT message {
+       inout Gtp1cUnitdata, Gtp1uUnitdata;
+} with { extension "internal" };
+
+signature GTPEM_register_imsi(hexstring imsi);
+signature GTPEM_register_teid(OCT4 teid);
+
+type port GTPEM_PROC_PT procedure {
+       inout GTPEM_register_imsi, GTPEM_register_teid;
+} with { extension "internal" };
+
+/***********************************************************************
+ * Client Compoennt
+ ***********************************************************************/
+
+type component GTP_ConnHdlr {
+       port GTPEM_PT GTP;
+       port GTPEM_PROC_PT GTP_PROC;
+};
+
+function f_gtp_register_imsi(hexstring imsi) runs on GTP_ConnHdlr {
+       GTP_PROC.call(GTPEM_register_imsi:{imsi}) {
+               [] GTP_PROC.getreply(GTPEM_register_imsi:{imsi});
+       }
+}
+
+function f_gtp_register_teid(OCT4 teid) runs on GTP_ConnHdlr {
+       GTP_PROC.call(GTPEM_register_teid:{teid}) {
+               [] GTP_PROC.getreply(GTPEM_register_teid:{teid});
+       }
+}
+
+}
diff --git a/library/GTP_Templates.ttcn b/library/GTP_Templates.ttcn
new file mode 100644
index 0000000..02a31b6
--- /dev/null
+++ b/library/GTP_Templates.ttcn
@@ -0,0 +1,518 @@
+module GTP_Templates {
+
+       import from General_Types all;
+       import from Osmocom_Types all;
+       import from GTPC_Types all;
+       import from GTPU_Types all;
+       import from GTP_CodecPort all;
+       import from IPCP_Types all;
+
+       /* generalized GTP-C receive template */
+       template PDU_GTPC tr_GTP1C_PDU(template OCT1 msg_type, template OCT4 
teid, template GTPC_PDUs pdu := ?) := {
+               /* N-PDU Number flag (PN) shall be set to '0'. A GTP-C receiver 
shall not return an
+                * error if this flag is set to '1'. */
+               pn_bit := '0'B,
+               /* Sequence number flag (S) shall be set to '1'. */
+               s_bit := '1'B,
+               e_bit := ?,
+               spare := ?,
+               /* Protocol Type flag (PT) shall be set to '1'.*/
+               pt := '1'B,
+               /* Version shall be set to decimal 1 ('001'). */
+               version := '001'B,
+               messageType := msg_type,
+               lengthf := ?,
+               teid := teid,
+               opt_part := *,
+               gtpc_pdu := pdu
+       }
+
+       /* generalized GTP-C send template */
+       template PDU_GTPC ts_GTP1C_PDU(OCT1 msg_type, OCT4 teid, GTPC_PDUs pdu, 
uint16_t seq_nr) := {
+               /* N-PDU Number flag (PN) shall be set to '0'. A GTP-C receiver 
shall not return an
+                * error if this flag is set to '1'. */
+               pn_bit := '0'B,
+               /* Sequence number flag (S) shall be set to '1'. */
+               s_bit := '1'B,
+               e_bit := '0'B,
+               spare := '0'B,
+               /* Protocol Type flag (PT) shall be set to '1'.*/
+               pt := '1'B,
+               /* Version shall be set to decimal 1 ('001'). */
+               version := '001'B,
+               messageType := msg_type,
+               lengthf := 0,   /* we assume encoder overwrites this */
+               teid := teid,
+               opt_part := {
+                       sequenceNumber := int2oct(seq_nr, 2),
+                       npduNumber := '00'O,
+                       nextExtHeader := '00'O,
+                       gTPC_extensionHeader_List := omit
+               },
+               gtpc_pdu := pdu
+       }
+
+       /* recovery IE */
+       template Recovery_gtpc ts_Recovery(OCT1 restart_counter) := {
+               type_gtpc := '0E'O,
+               restartCounter := restart_counter
+       }
+
+       template Recovery_gtpc tr_Recovery(template OCT1 restart_counter) := {
+               type_gtpc := '0E'O,
+               restartCounter := restart_counter
+       }
+
+       /* template matching reception of GTP-C echo-request */
+       template Gtp1cUnitdata tr_GTPC_MsgType(template GtpPeer peer, template 
OCT1 msg_type, template OCT4 teid, template GTPC_PDUs pdus := ?) := {
+               peer := peer,
+               gtpc := tr_GTP1C_PDU(msg_type, teid, pdus)
+       }
+
+       /* template matching reception of GTP-C echo-request */
+       template Gtp1cUnitdata tr_GTPC_PING(template GtpPeer peer) := 
tr_GTPC_MsgType(peer, echoRequest, '00000000'O);
+
+       template GTPC_PDUs tr_EchoRespPDU(template OCT1 restart_counter) := {
+               echoResponse := {
+                       recovery := tr_Recovery(restart_counter),
+                       private_extension_gtpc := *
+               }
+       }
+
+       /* template matching reception of GTP-C echo-response */
+       template Gtp1cUnitdata tr_GTPC_PONG(template GtpPeer peer) := 
tr_GTPC_MsgType(peer, echoResponse, '00000000'O, tr_EchoRespPDU(?));
+
+       template GTPC_PDUs ts_EchoRespPDU(OCT1 restart_counter) := {
+               echoResponse := {
+                       recovery := ts_Recovery(restart_counter),
+                       private_extension_gtpc := omit
+               }
+       }
+
+       /* master template for senidng a GTP-C echo response */
+       template Gtp1cUnitdata ts_GTPC_PONG(GtpPeer peer, uint16_t seq, OCT1 
rest_ctr) := {
+               peer := peer,
+               gtpc := ts_GTP1C_PDU(echoResponse, '00000000'O, 
valueof(ts_EchoRespPDU(rest_ctr)), seq)
+       }
+
+       template GTPC_PDUs ts_EchoReqPDU := {
+               echoRequest := {
+                       private_extension_gtpc := omit
+               }
+       }
+
+       /* master template for sending a GTP-C echo request */
+       template Gtp1cUnitdata ts_GTPC_PING(GtpPeer peer, uint16_t seq) := {
+               peer := peer,
+               gtpc := ts_GTP1C_PDU(echoRequest, '00000000'O, 
valueof(ts_EchoReqPDU), seq)
+       }
+
+       template EndUserAddress t_EuaIPv4(template OCT4 ip_addr) := {
+               type_gtpc := '80'O,
+               endUserAddress := {
+                       endUserAddressIPv4 := {
+                               lengthf := 2,
+                               pdp_typeorg := '0001'B,
+                               spare := '1111'B,
+                               pdp_typenum := '21'O,
+                               ipv4_address := ip_addr
+                       }
+               }
+       }
+       template EndUserAddress t_EuaIPv4Dyn := t_EuaIPv4(omit);
+       template EndUserAddress tr_EuaIPv4(template OCT4 ip_addr) modifies 
t_EuaIPv4 := {
+               endUserAddress := {
+                       endUserAddressIPv4 := {
+                               lengthf := 2+lengthof(ip_addr)
+                       }
+               }
+       }
+
+       template EndUserAddress t_EuaIPv6(template OCT16 ip_addr) := {
+               type_gtpc := '80'O,
+               endUserAddress := {
+                       endUserAddressIPv6 := {
+                               lengthf := 2,
+                               pdp_typeorg := '0001'B,
+                               spare := '1111'B,
+                               pdp_typenum := '57'O,
+                               ipv6_address := ip_addr
+                       }
+               }
+       }
+       template EndUserAddress t_EuaIPv6Dyn := t_EuaIPv6(omit);
+       template EndUserAddress tr_EuaIPv6(template OCT16 ip_addr) modifies 
t_EuaIPv6 := {
+               endUserAddress := {
+                       endUserAddressIPv6 := {
+                               lengthf := 2+lengthof(ip_addr)
+                       }
+               }
+       }
+
+       template AccessPointName ts_APN(octetstring apn) := {
+               type_gtpc := '83'O,
+               lengthf := lengthof(apn),
+               apn_value := apn
+       }
+
+       template GSN_Address_GTPC ts_GsnAddr(octetstring ip_addr) := {
+               type_gtpc := '85'O,
+               lengthf := lengthof(ip_addr),
+               addressf := ip_addr
+       }
+
+       template MSISDN ts_Msisdn(octetstring msisdn) := {
+               type_gtpc := '86'O,
+               lengthf := lengthof(msisdn),
+               msisdn := msisdn
+       }
+
+       template QualityOfServiceProfile ts_QosDefault := {
+               type_gtpc := '87'O,
+               lengthf := 4,
+               allocRetensionPrio := '00'O,
+               qos_ProfileValue := {
+                       reliabilityClass := '011'B,
+                       delayClass := '001'B,
+                       spare1 := '00'B,
+                       precedenceClass := '010'B,
+                       spare2 := '0'B,
+                       peakThroughput := '1001'B,
+                       meanThroughput := '11111'B,
+                       spare3 := '000'B,
+                       deliverErroneusSDU := omit,
+                       deliveryOrder := omit,
+                       trafficClass := omit,
+                       maxSDUSize := omit,
+                       maxBitrateUplink := omit,
+                       maxBitrateDownlink := omit,
+                       sduErrorRatio := omit,
+                       residualBER := omit,
+                       trafficHandlingPriority := omit,
+                       transferDelay := omit,
+                       guaranteedBitRateUplink := omit,
+                       guaranteedBitRateDownlink := omit,
+                       sourceStatisticsDescriptor := omit,
+                       signallingIndication := omit,
+                       spare4 := omit,
+                       maxBitrateDownlinkExt := omit,
+                       guaranteedBitRateDownlinkExt := omit,
+                       maxBitrateUplinkExt := omit,
+                       guaranteedBitRateUplinkExt := omit
+               }
+       }
+
+       template IMSI_gtpc ts_Imsi(hexstring digits) := {
+               type_gtpc := '02'O,
+               digits := digits,
+               padding := 'F'H
+       }
+
+       template GTPC_PDUs ts_CreatePdpPDU(hexstring imsi, OCT1 restart_ctr, 
OCT4 teid_data, OCT4 teid_ctrl,
+                                          BIT4 nsapi, EndUserAddress eua, 
octetstring apn,
+                                          octetstring sgsn_ip_sign, 
octetstring sgsn_ip_data,
+                                          octetstring msisdn, template 
ProtConfigOptions pco := omit) := {
+               createPDPContextRequest := {
+                       imsi := ts_Imsi(imsi),
+                       rai := omit,
+                       recovery := ts_Recovery(restart_ctr),
+                       selectionMode := {
+                               type_gtpc := '0F'O,
+                               selectModeValue := '00'B,
+                               spare := '111111'B
+                       },
+                       teidDataI := {
+                               type_gtpc := '00'O,
+                               teidDataI := teid_data
+                       },
+                       teidControlPlane := {
+                               type_gtpc := '00'O,
+                               teidControlPlane := teid_ctrl
+                       },
+                       nsapi := {
+                               type_gtpc := '00'O,
+                               nsapi := nsapi,
+                               unused := '0000'B
+                       },
+                       linked_nsapi := omit,
+                       charging_char := omit,
+                       trace_ref := omit,
+                       trace_type := omit,
+                       endUserAddress := eua,
+                       accessPointName := ts_APN(apn),
+                       protConfigOptions := pco,
+                       sgsn_addr_signalling := ts_GsnAddr(sgsn_ip_sign),
+                       sgsn_addr_traffic := ts_GsnAddr(sgsn_ip_data),
+                       msisdn := ts_Msisdn(msisdn),
+                       qualityOfServiceProfile := ts_QosDefault,
+                       tft := omit,
+                       triggerId := omit,
+                       omcId := omit,
+                       commonFlags := omit,
+                       aPN_Restriction := omit,
+                       ratType := omit,
+                       userLocationInformation := omit,
+                       mS_TimeZone := omit,
+                       imeisv := omit,
+                       camelChargingInformationContainer := omit,
+                       additionalTraceInfo := omit,
+                       correlationID := omit,
+                       evolvedAllocationRetentionPriorityI := omit,
+                       extendedCommonFlags := omit,
+                       userCSGInformation := omit,
+                       aPN_AMBR := omit,
+                       signallingPriorityIndication := omit,
+                       cN_OperatorSelectionEntity := omit,
+                       private_extension_gtpc := omit
+               }
+       }
+
+       template Gtp1cUnitdata ts_GTPC_CreatePDP(GtpPeer peer, uint16_t seq, 
hexstring imsi,
+                                                OCT1 restart_ctr, OCT4 
teid_data,
+                                                OCT4 teid_ctrl, BIT4 nsapi, 
EndUserAddress eua,
+                                                octetstring apn, octetstring 
sgsn_ip_sign,
+                                                octetstring sgsn_ip_data, 
octetstring msisdn,
+                                                template ProtConfigOptions pco 
:= omit) := {
+               peer := peer,
+               gtpc := ts_GTP1C_PDU(createPDPContextRequest, '00000000'O,
+                                       valueof(ts_CreatePdpPDU(imsi, 
restart_ctr, teid_data, teid_ctrl,
+                                                               nsapi, eua, 
apn, sgsn_ip_sign,
+                                                               sgsn_ip_data, 
msisdn, pco)), seq)
+       }
+
+       /* PCO send base template */
+       template ProtConfigOptions ts_PCO := {
+               type_gtpc := '84'O,
+               lengthf := 0,
+               configProtocol := '000'B,
+               spare := '0000'B,
+               extension0 := '1'B,
+               protocols := {}
+       }
+       /* PCO receive base template */
+       template ProtConfigOptions tr_PCO := {
+               type_gtpc := '84'O,
+               lengthf := ?,
+               configProtocol := '000'B,
+               spare := ?,
+               extension0 := '1'B,
+               protocols := {}
+       }
+
+       template ProtConfigOptions ts_PCO_IPv6_DNS modifies ts_PCO := {
+               protocols := {
+                       { protocolID := '0003'O, lengthProtoID := 0, 
protoIDContents := ''O }
+               }
+       }
+       template ProtConfigOptions tr_PCO_IPv6_DNS_resp(template OCT16 
contents) modifies tr_PCO := {
+               protocols := {
+                       *, { protocolID := '0003'O, lengthProtoID := 16, 
protoIDContents := contents }, *
+               }
+       }
+
+       template ProtConfigOptions ts_PCO_IPv4_DNS_IPCP modifies ts_PCO := {
+               protocols := {
+                       /* dummy PAP entry to check if our parser in the GGSN 
can properly iterate over
+                        * the list of protocols, see Change-Id 
Icc2e6716c33d78d3c3e000f529806228d8aa155e */
+                       { protocolID := 'C023'O, lengthProtoID := 0, 
protoIDContents := ''O },
+                       { protocolID := '8021'O, lengthProtoID := 16, 
protoIDContents :=
+                                                               
enc_IpcpPacket(valueof(ts_IPCP_ReqDNS)) }
+               }
+       }
+
+       template ProtocolElement tr_PCO_Proto(OCT2 prot_id) := {
+               protocolID := prot_id,
+               lengthProtoID := ?,
+               protoIDContents := ?
+       }
+       template ProtConfigOptions tr_PCO_Contains(OCT2 prot_id) modifies 
tr_PCO := {
+               protocols := { *, tr_PCO_Proto(prot_id), * }
+       }
+
+       template ProtConfigOptions ts_PCO_IPv4_DNS_CONT modifies ts_PCO := {
+               protocols := {
+                       { protocolID := '000d'O, lengthProtoID := 0, 
protoIDContents := ''O }
+               }
+       }
+       template ProtConfigOptions tr_PCO_IPv4_DNS_CONT_resp(template OCT4 
contents) modifies tr_PCO := {
+               protocols := {
+                       *, { protocolID := '000d'O, lengthProtoID := 4, 
protoIDContents := contents }, *
+               }
+       }
+
+       /* extract a given protocol payload from PCO */
+       function f_PCO_extract_proto(ProtConfigOptions pco, OCT2 protocol, 
integer nth_match := 1) return octetstring {
+               var integer i;
+               var integer num_matches := 0;
+               for (i := 0; i < lengthof(pco.protocols); i := i + 1) {
+                       if (pco.protocols[i].protocolID == protocol) {
+                               num_matches := num_matches + 1;
+                               if (num_matches == nth_match) {
+                                       return pco.protocols[i].protoIDContents;
+                               }
+                       }
+               }
+               setverdict(fail);
+               return ''O;
+       }
+
+       template IpcpPacket tr_IPCP(template LcpCode code, template uint8_t 
identifier,
+                                   template IpcpOptionList opts) := {
+               code := code,
+               identifier := identifier,
+               len := ?,
+               options := opts
+       }
+       template IpcpOption tr_IPCP_PrimaryDns(template OCT4 addr) := {
+               code := IPCP_OPT_PrimaryDNS,
+               len := 6,
+               data := addr
+       }
+       template IpcpOption tr_IPCP_SecondaryDns(template OCT4 addr) := {
+               code := IPCP_OPT_SecondaryDNS,
+               len := 6,
+               data := addr
+       }
+       template IpcpPacket tr_IPCP_Ack_DNS(template uint8_t identifier := ?, 
template OCT4 dns1 := ?,
+                                           template OCT4 dns2 := ?) :=
+               tr_IPCP(LCP_Configure_Ack, identifier,
+                               { *, tr_IPCP_PrimaryDns(dns1), *, 
tr_IPCP_SecondaryDns(dns2), * });
+
+       template IpcpPacket ts_IPCP(LcpCode code, uint8_t identifier, template 
IpcpOptionList opts) := {
+               code := code,
+               identifier := identifier,
+               len := 0,       /* overwritten */
+               options := opts
+       }
+       template IpcpPacket ts_IPCP_ReqDNS(uint8_t identifier := 0) :=
+               ts_IPCP(LCP_Configure_Request, identifier,
+                       { tr_IPCP_PrimaryDns('00000000'O), 
tr_IPCP_SecondaryDns('00000000'O) });
+
+       function f_teardown_ind_IE(in template BIT1 ind) return template 
TearDownInd {
+/*
+               if (not isvalue(ind)) {
+                       return omit;
+               }
+*/
+               var TearDownInd ret := {
+                       type_gtpc := '13'O,
+                       tdInd := valueof(ind),
+                       spare:= '0000000'B
+               }
+               return ret;
+       }
+
+       template GTPC_PDUs ts_DeletePdpPDU(BIT4 nsapi, template BIT1 
teardown_ind) := {
+               deletePDPContextRequest := {
+                       cause := omit,
+                       tearDownIndicator := f_teardown_ind_IE(teardown_ind),
+                       nsapi := {
+                               type_gtpc := '14'O,
+                               nsapi := nsapi,
+                               unused := '0000'B
+                       },
+                       protConfigOptions := omit,
+                       userLocationInformation := omit,
+                       mS_TimeZone := omit,
+                       extendedCommonFlags := omit,
+                       uLI_Timestamp := omit,
+                       private_extension_gtpc := omit
+               }
+       }
+
+       template Gtp1cUnitdata ts_GTPC_DeletePDP(GtpPeer peer, uint16_t seq, 
OCT4 teid,
+                                                BIT4 nsapi, template BIT1 
teardown_ind) := {
+               peer := peer,
+               gtpc := ts_GTP1C_PDU(deletePDPContextRequest, teid,
+                                       valueof(ts_DeletePdpPDU(nsapi, 
teardown_ind)), seq)
+       }
+
+
+       /* GTP-U */
+
+       template PDU_GTPU tr_GTP1U_PDU(template OCT1 msg_type, template OCT4 
teid, template GTPU_IEs ies := ?) := {
+               pn_bit := ?,
+               s_bit := ?,
+               e_bit := ?,
+               spare := ?,
+               /* Protocol Type flag (PT) shall be set to '1' in GTP */
+               pt := '1'B,
+               /* Version shall be set to decimal 1 ('001'). */
+               version := '001'B,
+               messageType := msg_type,
+               lengthf := ?,
+               teid := teid,
+               opt_part := *,
+               gtpu_IEs := ies
+       }
+
+       /* generalized GTP-U send template */
+       template PDU_GTPU ts_GTP1U_PDU(OCT1 msg_type, uint16_t seq, OCT4 teid, 
GTPU_IEs ies) := {
+               /* N-PDU Number flag (PN): the GTP-U header contains a 
meaningful N-PDU Number field if the PN
+                * flag is set to 1. */
+               pn_bit := '0'B, /* we assume the encoder overwrites this if an 
optional part is given */
+               /* If the Sequence Number flag (S) is set to '1' the sequence 
number field is present and
+                * meaningful otherwise it is set to '0'. For GTP-U messages 
Echo Request, Echo Response,
+                * Error Indication and Supported Extension Headers 
Notification, the S flag shall be set to '1'. */
+               s_bit := '1'B,  /* we assume the encoder overwrites this if an 
optional part is given */
+               /* Extension header presence */
+               e_bit := '0'B,
+               spare := '0'B,
+               /* Protocol Type flag (PT) shall be set to '1' in GTP */
+               pt := '1'B,
+               /* Version shall be set to decimal 1 ('001'). */
+               version := '001'B,
+               messageType := msg_type,
+               lengthf := 0,   /* we assume encoder overwrites this */
+               teid := teid,
+               opt_part :=  {
+                       sequenceNumber := int2oct(seq, 2),
+                       npduNumber := '00'O,
+                       nextExtHeader := '00'O,
+                       gTPU_extensionHeader_List := omit
+               },
+               gtpu_IEs := ies
+       }
+
+       template Gtp1uUnitdata tr_GTPU_MsgType(template GtpPeer peer, template 
OCT1 msg_type, template OCT4 teid) := {
+               peer := peer,
+               gtpu := tr_GTP1U_PDU(msg_type, teid)
+       }
+
+
+       /* template matching reception of GTP-U echo-request */
+       template Gtp1uUnitdata tr_GTPU_PING(template GtpPeer peer) := 
tr_GTPU_MsgType(peer, echoRequest, '00000000'O);
+
+       /* template matching reception of GTP-U GPDU */
+       template GTPU_IEs t_GPDU(template octetstring data) := {
+               g_PDU_IEs := {
+                       data := data
+               }
+       }
+       template Gtp1uUnitdata tr_GTPU_GPDU(template GtpPeer peer, template 
OCT4 teid, template octetstring data := ?) := {
+               peer := peer,
+               gtpu := tr_GTP1U_PDU('FF'O, teid, t_GPDU(data))
+       }
+
+       template GTPU_IEs ts_UEchoRespPDU(OCT1 restart_counter) := {
+               echoResponse_IEs := {
+                       recovery_gtpu := {
+                               type_gtpu := '00'O, /* we assume encoder fixes? 
*/
+                               restartCounter := restart_counter
+                       },
+                       private_extension_gtpu := omit
+               }
+       }
+
+       /* master template for sending a GTP-U echo response */
+       template Gtp1uUnitdata ts_GTPU_PONG(GtpPeer peer, uint16_t seq, OCT1 
rest_ctr) := {
+               peer := peer,
+               gtpu := ts_GTP1U_PDU(echoResponse, seq, '00000000'O, 
valueof(ts_UEchoRespPDU(rest_ctr)))
+       }
+
+       /* master template for sending a GTP-U user plane data */
+       template Gtp1uUnitdata ts_GTP1U_GPDU(GtpPeer peer, uint16_t seq, OCT4 
teid, octetstring data) := {
+               peer := peer,
+               gtpu := ts_GTP1U_PDU('FF'O, seq, teid, { g_PDU_IEs := { data := 
data }})
+       }
+}

-- 
To view, visit https://gerrit.osmocom.org/6567
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I384e59738a9e0fc0186b69f0806f217a2a8d8a4b
Gerrit-PatchSet: 1
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <lafo...@gnumonks.org>

Reply via email to