From eded9ad5781d36f5198cd02252052384538c6440 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 17 Feb 2018 20:57:34 +0100 Subject: [PATCH] sgsn: First PDP CTX ACT test: TC_attach_pdp_act Change-Id: Ia1bfaca99a2a70bb097e2ee44f54e4a31b849a1b --- library/GSUP_Types.ttcn | 50 ++++++++++- library/GTP_Templates.ttcn | 65 ++++++++++++++ library/L3_Templates.ttcn | 124 ++++++++++++++++++++++++++ sgsn/SGSN_Tests.ttcn | 178 ++++++++++++++++++++++++++++++++++++- sgsn/gen_links.sh | 6 ++ sgsn/regen_makefile.sh | 2 +- 6 files changed, 420 insertions(+), 5 deletions(-) diff --git a/library/GSUP_Types.ttcn b/library/GSUP_Types.ttcn index 0a2199928..5e6b20a3a 100644 --- a/library/GSUP_Types.ttcn +++ b/library/GSUP_Types.ttcn @@ -105,7 +105,12 @@ type record GSUP_IE { msisdn, tag = OSMO_GSUP_MSISDN_IE; hlr_number, tag = OSMO_GSUP_HLR_NUMBER_IE; cn_domain, tag = OSMO_GSUP_CN_DOMAIN_IE; - charg_char, tag = OSMO_GSUP_CHARG_CHAR_IE)" + pdp_info, tag = OSMO_GSUP_PDP_INFO_IE; + apn, tag = OSMO_GSUP_ACCESS_POINT_NAME_IE; + pdp_qos, tag = OSMO_GSUP_PDP_QOS_IE; + pdp_type, tag = OSMO_GSUP_PDP_TYPE_IE; + charg_char, tag = OSMO_GSUP_CHARG_CHAR_IE; + )" }; type record of GSUP_IE GSUP_IEs; @@ -116,7 +121,6 @@ type union GSUP_IeValue { GSUP_CancelType cancel_type, //boolean pdp_info_compl, //boolean freeze_ptmsi, - GSUP_IEs pdp_info, GSUP_IEs auth_tuple, octetstring auts, octetstring rand, @@ -129,6 +133,11 @@ type union GSUP_IeValue { GSUP_MSISDN msisdn, octetstring hlr_number, GSUP_CnDomain cn_domain, + /* PDP context + nested IEs */ + GSUP_IEs pdp_info, + octetstring apn, + octetstring pdp_qos, + OCT2 pdp_type, octetstring charg_char }; @@ -217,6 +226,35 @@ template GSUP_IE ts_GSUP_IE_AuthTuple2G3G(octetstring rand, octetstring sres, } } +template GSUP_IE ts_GSUP_IE_PdpInfo(octetstring apn, octetstring pdp_type, octetstring pdp_qos) := { + tag := OSMO_GSUP_PDP_INFO_IE, + len := 0, /* overwritten */ + val := { + pdp_info := { + valueof(ts_GSUP_IE_APN(apn)), + valueof(ts_GSUP_IE_PDP_TYPE(pdp_type)), + valueof(ts_GSUP_IE_PDP_QOS(pdp_qos)) + } + } +} + +template (value) GSUP_IE ts_GSUP_IE_PDP_TYPE(OCT2 pdp_type) := { + tag := OSMO_GSUP_PDP_TYPE_IE, + len := 0, + val := { + pdp_type := pdp_type + } +} + +template (value) GSUP_IE ts_GSUP_IE_PDP_QOS(octetstring pdp_qos) := { + tag := OSMO_GSUP_PDP_QOS_IE, + len := 0, + val := { + pdp_qos := pdp_qos + } +} + + template GSUP_PDU tr_GSUP(template GSUP_MessageType msgt := ?, template GSUP_IEs ies := *) := { msg_type := msgt, ies := ies @@ -428,6 +466,14 @@ template (value) GSUP_IE ts_GSUP_IE_RES(octetstring res) := { } } +template (value) GSUP_IE ts_GSUP_IE_APN(octetstring apn) := { + tag := OSMO_GSUP_ACCESS_POINT_NAME_IE, + len := 0, /* overwritten */ + val := { + apn := apn + } +} + } with { encode "RAW"; variant "FIELDORDER(msb)" } diff --git a/library/GTP_Templates.ttcn b/library/GTP_Templates.ttcn index 02a31b6b2..b64289b72 100644 --- a/library/GTP_Templates.ttcn +++ b/library/GTP_Templates.ttcn @@ -280,6 +280,71 @@ module GTP_Templates { sgsn_ip_data, msisdn, pco)), seq) } + + template NSAPI_GTPC ts_NSAPI(BIT4 nsapi) := { + type_gtpc := '14'O, + nsapi := nsapi, + unused := '0000'B + } + + template ReorderingRequired ts_ReorderReq(boolean req := false) := { + type_gtpc := '08'O, + reordreq := bool2bit(req), + spare := '0000000'B + } + + template GTPC_PDUs ts_CreatePdpRespPDU(OCT1 cause, OCT4 teid_data, OCT4 teid_ctrl, BIT4 nsapi, + octetstring ggsn_ip_sign, octetstring ggsn_ip_data, + template EndUserAddress eua := omit, + template ProtConfigOptions pco := omit) := { + createPDPContextResponse := { + cause := { '00'O, cause }, + reorderingRequired := ts_ReorderReq(false), + recovery := omit, + teidDataI := { + type_gtpc := '00'O, + teidDataI := teid_data + }, + teidControlPlane := { + type_gtpc := '00'O, + teidControlPlane := teid_ctrl + }, + nsapi := ts_NSAPI(nsapi), + chargingID := omit, + endUserAddress := eua, + protConfigOptions := pco, + ggsn_addr_controlPlane := ts_GsnAddr(ggsn_ip_sign), + ggsn_addr_traffic := ts_GsnAddr(ggsn_ip_data), + alt_ggsn_addr_controlPane := omit, + alt_ggsn_addr_traffic := omit, + qualityOfServiceProfile := ts_QosDefault, + commonFlags := omit, + aPN_Restriction := omit, + mS_InfoChangeReportingAction := omit, + bearerControlMode := omit, + evolvedAllocationRetentionPriorityI := omit, + extendedCommonFlag := omit, + csg_information_reporting_action := omit, + aPN_AMBR := omit, + gGSN_BackOffTime := omit, + private_extension_gtpc := omit + } + } + + template Gtp1cUnitdata ts_GTPC_CreatePdpResp(GtpPeer peer, uint16_t seq, OCT4 teid, + OCT1 cause, + OCT4 teid_ctrl, OCT4 teid_data, + BIT4 nsapi, octetstring ggsn_ip_sign, + octetstring ggsn_ip_data, + template EndUserAddress eua := omit, + template ProtConfigOptions pco := omit) := { + peer := peer, + gtpc := ts_GTP1C_PDU(createPDPContextResponse, teid, + valueof(ts_CreatePdpRespPDU(cause, teid_data, teid_ctrl, nsapi, + ggsn_ip_sign, ggsn_ip_data, + eua, pco)), seq) + } + /* PCO send base template */ template ProtConfigOptions ts_PCO := { type_gtpc := '84'O, diff --git a/library/L3_Templates.ttcn b/library/L3_Templates.ttcn index 9bd74db80..73d28181b 100644 --- a/library/L3_Templates.ttcn +++ b/library/L3_Templates.ttcn @@ -1766,6 +1766,130 @@ template PDU_L3_SGSN_MS tr_GMM_DET_ACCEPT_MT := { } } + +function ts_ApnTLV(template (omit) octetstring apn) return template (omit) AccessPointNameTLV { + if (istemplatekind(apn, "omit")) { + return omit; + } else { + var template (omit) AccessPointNameTLV ret := { + elementIdentifier := '28'O, + lengthIndicator := 0, /* overwritten */ + accessPointNameValue := apn + } + return ret; + } +} + +function ts_PcoTLV(template (omit) ProtocolConfigOptionsV pco) + return template (omit) ProtocolConfigOptionsTLV { + if (istemplatekind(pco, "omit")) { + return omit; + } else { + var template (omit) ProtocolConfigOptionsTLV ret := { + elementIdentifier := '27'O, + lengthIndicator := 0, /* overwritten */ + protocolConfigOptionsV := pco + } + return ret; + } +} + +template (value) PDU_L3_MS_SGSN ts_SM_ACT_PDP_REQ(BIT3 tid, BIT4 nsapi, BIT4 sapi, QoSV qos, + PDPAddressV addr, + template (omit) octetstring apn := omit, + template (omit) ProtocolConfigOptionsV pco := omit + ) := { + discriminator := '0000'B, /* overwritten */ + tiOrSkip := { + transactionId := { + tio := tid, + tiFlag := '0'B, + tIExtension := omit + } + }, + msgs := { + gprs_sm := { + activatePDPContextRequest := { + messageType := '00000000'B, /* overwritten */ + requestedNSAPI := { nsapi, '0000'B }, + requestedLLCSAPI := { sapi, '0000'B }, + requestedQoS := { + lengthIndicator := 0, /* overwritten */ + qoSV := qos + }, + requestedPDPaddress := { + lengthIndicator := 0, /* overwritten */ + pdpAddressV := addr + }, + accessPointName := ts_ApnTLV(apn), + protocolConfigOpts := ts_PcoTLV(pco), + requestType := omit, + deviceProperties := omit, + nBIFOM_Container := omit + } + } + } +} + +template PDU_L3_SGSN_MS tr_SM_ACT_PDP_REJ(template BIT3 tid := ?, template OCT1 cause := ?) := { + discriminator := '1010'B, + tiOrSkip := { + transactionId := { + tio := tid, + tiFlag := '1'B, + tIExtension := omit + } + }, + msgs := { + gprs_sm := { + activatePDPContextReject := { + messageType := '01001111'B, + smCause := cause, + protocolConfigOpts := *, + backOffTimer := *, + reAttemptIndicator := *, + nBIFOM_Container := * + } + } + } +} + +template PDU_L3_SGSN_MS tr_SM_ACT_PDP_ACCEPT(template BIT3 tid := ?, template BIT4 sapi := ?, + template QoSV qos := ?) +:= { + discriminator := '1010'B, + tiOrSkip := { + transactionId := { + tio := tid, + tiFlag := '1'B, + tIExtension := omit + } + }, + msgs := { + gprs_sm := { + activatePDPContextAccept := { + messageType := '01000010'B, + negotiatedLLCSAPI := { sapi, '0000'B }, + negotiatedQoS := { + lengthIndicator := ?, + qoSV := qos + }, + radioPriority := ?, + spare := '0000'B, + pdpAddress := *, + protocolConfigOpts := *, + packetFlowID := *, + sMCause2 := *, + connectivityType := *, + wLANOffloadIndication := *, + nBIFOM_Container := * + } + } + } +} + + + private function f_concat_pad(integer tot_len, hexstring prefix, integer suffix) return hexstring { var integer suffix_len := tot_len - lengthof(prefix); var charstring suffix_ch := int2str(suffix); diff --git a/sgsn/SGSN_Tests.ttcn b/sgsn/SGSN_Tests.ttcn index 3cf16573d..9209c6938 100644 --- a/sgsn/SGSN_Tests.ttcn +++ b/sgsn/SGSN_Tests.ttcn @@ -18,13 +18,21 @@ import from GSUP_Emulation all; import from GSUP_Types all; import from IPA_Emulation all; +import from GTP_Emulation all; +import from GTP_Templates all; +import from GTP_CodecPort all; +import from GTPC_Types all; +import from GTPU_Types all; + import from TELNETasp_PortType all; import from Osmocom_VTY_Functions all; + modulepar { /* IP/port on which we run our internal GSUP/HLR emulation */ charstring mp_hlr_ip := "127.0.0.1"; integer mp_hlr_port := 4222; + charstring mp_ggsn_ip := "127.0.0.2"; }; type record GbInstance { @@ -41,12 +49,14 @@ type component test_CT { /* only to get events from IPA underneath GSUP */ port IPA_CTRL_PT GSUP_IPA_EVENT; + var GTP_Emulation_CT vc_GTP; + port TELNETasp_PT SGSNVTY; var boolean g_initialized := false; }; -type component BSSGP_ConnHdlr extends BSSGP_Client_CT, GSUP_ConnHdlr { +type component BSSGP_ConnHdlr extends BSSGP_Client_CT, GSUP_ConnHdlr, GTP_ConnHdlr { var BSSGP_ConnHdlrPars g_pars; timer g_Tguard; } @@ -118,6 +128,21 @@ private function f_init_gsup(charstring id) runs on test_CT { } } +private function f_init_gtp(charstring id) runs on test_CT { + id := id & "-GTP"; + + var GtpEmulationCfg gtp_cfg := { + gtpc_bind_ip := mp_ggsn_ip, + gtpc_bind_port := GTP1C_PORT, + gtpu_bind_ip := mp_ggsn_ip, + gtpu_bind_port := GTP1U_PORT, + sgsn_role := false + }; + + vc_GTP := GTP_Emulation_CT.create(id); + vc_GTP.start(GTP_Emulation.main(gtp_cfg)); +} + private function f_init_vty() runs on test_CT { map(self:SGSNVTY, system:SGSNVTY); f_vty_set_prompts(SGSNVTY); @@ -147,6 +172,7 @@ function f_init() runs on test_CT { f_init_gb(g_gb[0]); f_init_gsup("SGSN_Test"); + f_init_gtp("SGSN_Test"); f_init_vty(); } @@ -184,6 +210,9 @@ runs on test_CT return BSSGP_ConnHdlr { connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT); connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC); + connect(vc_conn:GTP, vc_GTP:CLIENT); + connect(vc_conn:GTP_PROC, vc_GTP:CLIENT_PROC); + vc_conn.start(f_handler_init(fn, id, pars)); return vc_conn; } @@ -205,6 +234,8 @@ runs on BSSGP_ConnHdlr { f_bssgp_client_register(g_pars.imsi, g_pars.tlli, g_pars.bssgp_cell_id); /* tell GSUP dispatcher to send this IMSI to us */ f_create_gsup_expect(hex2str(g_pars.imsi)); + /* tell GTP dispatcher to send this IMSI to us */ + f_gtp_register_imsi(g_pars.imsi); g_Tguard.start(pars.t_guard); activate(as_Tguard()); @@ -349,9 +380,12 @@ private function f_mi_get_lv() runs on BSSGP_ConnHdlr return MobileIdentityLV { } private function f_gmm_gsup_lu_isd() runs on BSSGP_ConnHdlr { + var GSUP_PDU gsup; /* Expect MSC to perform LU with HLR */ GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); - GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn)); + gsup := valueof(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn)); + gsup.ies := gsup.ies & { valueof(ts_GSUP_IE_PdpInfo(char2oct("*"), '0121'O, ''O)) }; + GSUP.send(gsup); GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi)); GSUP.send(ts_GSUP_UL_RES(g_pars.imsi)); } @@ -720,7 +754,146 @@ testcase TC_detach_poweroff() runs on test_CT { vc_conn.done; } +type record PdpActPars { + BIT3 tid, + BIT4 nsapi, + BIT4 sapi, + QoSV qos, + PDPAddressV addr, + octetstring apn optional, + ProtocolConfigOptionsV pco optional, + OCT1 exp_rej_cause optional, + OCT4 ggsn_tei_c, + OCT4 ggsn_tei_u, + octetstring ggsn_ip_c, + octetstring ggsn_ip_u, + + GtpPeer sgsn, + OCT4 sgsn_tei_c optional, + OCT4 sgsn_tei_u optional +}; + +function f_pdp_ctx_act(PdpActPars apars) runs on BSSGP_ConnHdlr { + var boolean exp_rej := ispresent(apars.exp_rej_cause); + var Gtp1cUnitdata g_ud; + + BSSGP.send(ts_SM_ACT_PDP_REQ(apars.tid, apars.nsapi, apars.sapi, apars.qos, apars.addr, + apars.apn, apars.pco)); + if (not exp_rej) { + GTP.receive(tr_GTPC_MsgType(?, createPDPContextRequest, ?)) -> value g_ud { + var integer seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber); + var GTPC_PDUs gtpc_rx := g_ud.gtpc.gtpc_pdu; + apars.sgsn_tei_c := gtpc_rx.createPDPContextRequest.teidControlPlane.teidControlPlane; + apars.sgsn_tei_u := gtpc_rx.createPDPContextRequest.teidDataI.teidDataI; + var OCT1 cause := int2oct(128, 1); + GTP.send(ts_GTPC_CreatePdpResp(g_ud.peer, seq_nr, + apars.sgsn_tei_c, cause, + apars.ggsn_tei_c, apars.ggsn_tei_u, + apars.nsapi, + apars.ggsn_ip_c, apars.ggsn_ip_u)); + } + } + alt { + [exp_rej] BSSGP.receive(tr_BD_L3(tr_SM_ACT_PDP_REJ(apars.tid, apars.exp_rej_cause))) { + setverdict(pass); + } + [exp_rej] BSSGP.receive(tr_BD_L3(tr_SM_ACT_PDP_ACCEPT)) { + setverdict(fail, "Unexpected PDP CTX ACT ACC"); + } + [not exp_rej] BSSGP.receive(tr_BD_L3(tr_SM_ACT_PDP_REJ(apars.tid, ?))) { + setverdict(fail, "Unexpected PDP CTX ACT FAIL"); + } + [not exp_rej] BSSGP.receive(tr_BD_L3(tr_SM_ACT_PDP_ACCEPT(apars.tid, apars.sapi))) { + setverdict(pass); + } + } +} + +/* Table 10.5.156/3GPP TS 24.008 */ +template (value) QoSV t_QosDefault := { + reliabilityClass := '011'B, /* unacknowledged GTP+LLC, acknowledged RLC */ + delayClass := '100'B, /* best effort */ + spare1 := '00'B, + precedenceClass := '010'B, /* normal */ + spare2 := '0'B, + peakThroughput := '0000'B, /* subscribed */ + meanThroughput := '00000'B, /* subscribed */ + 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, + maxBitrateDownlinkExt2 := omit, + guaranteedBitRateDownlinkExt2 := omit, + maxBitrateUplinkExt2 := omit, + guaranteedBitRateUplinkExt2 := omit +} + +/* 10.5.6.4 / 3GPP TS 24.008 */ +template (value) PDPAddressV t_AddrIPv4dyn := { + pdpTypeOrg := '0001'B, /* IETF */ + spare := '0000'B, + pdpTypeNum := '21'O, /* IPv4 */ + addressInfo := omit +} +template (value) PDPAddressV t_AddrIPv6dyn := { + pdpTypeOrg := '0001'B, /* IETF */ + spare := '0000'B, + pdpTypeNum := '53'O, /* IPv6 */ + addressInfo := omit +} + +template (value) PdpActPars t_PdpActPars := { + tid := '000'B, + nsapi := '0101'B, /* < 5 are reserved */ + sapi := '0011'B, /* 3/5/9/11 */ + qos := t_QosDefault, + addr := t_AddrIPv4dyn, + apn := omit, + pco := omit, + exp_rej_cause := omit, + + /* FIXME: make below dynamic !! */ + ggsn_tei_c := '00010000'O, + ggsn_tei_u := '00020000'O, + ggsn_ip_c := '7F000001'O, + ggsn_ip_u := '7F000001'O, + + sgsn := { }, + sgsn_tei_c := omit, + sgsn_tei_u := omit +} + +private function f_TC_attach_pdp_act(charstring id) runs on BSSGP_ConnHdlr { + var PdpActPars apars := valueof(t_PdpActPars); + + /* first perform regular attach */ + f_TC_attach(id); + + f_pdp_ctx_act(apars); +} +testcase TC_attach_pdp_act() runs on test_CT { + var BSSGP_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_TC_attach_pdp_act), testcasename(), g_gb[0], 17); + vc_conn.done; +} control { @@ -739,6 +912,7 @@ control { execute( TC_detach_unknown_poweroff() ); execute( TC_detach_nopoweroff() ); execute( TC_detach_poweroff() ); + execute( TC_attach_pdp_act() ); } diff --git a/sgsn/gen_links.sh b/sgsn/gen_links.sh index bc2727df9..b45028865 100755 --- a/sgsn/gen_links.sh +++ b/sgsn/gen_links.sh @@ -63,6 +63,10 @@ DIR=$BASEDIR/titan.ProtocolModules.MobileL3_v13.4.0/src FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn MobileL3_RRM_Types.ttcn MobileL3_SMS_Types.ttcn MobileL3_SS_Types.ttcn MobileL3_Types.ttcn" gen_links $DIR $FILES +DIR=$BASEDIR/titan.ProtocolModules.GTP_v13.5.0/src +FILES="GTPC_EncDec.cc GTPC_Types.ttcn GTPU_EncDec.cc GTPU_Types.ttcn" +gen_links $DIR $FILES + DIR=../library FILES="General_Types.ttcn GSM_Types.ttcn GSM_RR_Types.ttcn Osmocom_Types.ttcn RLCMAC_Types.ttcn RLCMAC_CSN1_Types.ttcn RLCMAC_EncDec.cc " FILES+="NS_Emulation.ttcn NS_CodecPort.ttcn NS_CodecPort_CtrlFunct.ttcn NS_CodecPort_CtrlFunctDef.cc " @@ -73,4 +77,6 @@ FILES+="LLC_Templates.ttcn L3_Templates.ttcn L3_Common.ttcn " # IPA_Emulation + dependencies FILES+="IPA_Types.ttcn IPA_Emulation.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc Native_Functions.ttcn Native_FunctionDefs.cc GSUP_Types.ttcn GSUP_Emulation.ttcn MGCP_Types.ttcn RSL_Types.ttcn " +FILES+="GTP_CodecPort.ttcn GTP_CodecPort_CtrlFunct.ttcn GTP_CodecPort_CtrlFunctDef.cc GTP_Emulation.ttcn +GTP_Templates.ttcn IPCP_Types.ttcn " gen_links $DIR $FILES diff --git a/sgsn/regen_makefile.sh b/sgsn/regen_makefile.sh index c05506559..069116492 100755 --- a/sgsn/regen_makefile.sh +++ b/sgsn/regen_makefile.sh @@ -1,5 +1,5 @@ #!/bin/sh -FILES="*.ttcn BSSGP_EncDec.cc LLC_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc NS_CodecPort_CtrlFunctDef.cc RLCMAC_EncDec.cc Native_FunctionDefs.cc SDP_EncDec.cc SDP_parse_.tab.c lex.SDP_parse_.c TELNETasp_PT.cc IPA_CodecPort_CtrlFunctDef.cc" +FILES="*.ttcn BSSGP_EncDec.cc LLC_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc NS_CodecPort_CtrlFunctDef.cc RLCMAC_EncDec.cc Native_FunctionDefs.cc SDP_EncDec.cc SDP_parse_.tab.c lex.SDP_parse_.c TELNETasp_PT.cc IPA_CodecPort_CtrlFunctDef.cc GTPU_EncDec.cc GTPC_EncDec.cc GTP_CodecPort_CtrlFunctDef.cc" ../regen-makefile.sh SGSN_Tests.ttcn $FILES