From b8a4ac80a618134d3e1148340d670cbdd371fd10 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 23 Jun 2019 11:04:12 +0200 Subject: [PATCH] mme: initial skeleton for MME / SGsAP tetss Change-Id: Idbd54838daaf12acccc3253dc4278de75eaaaf31 --- library/SGsAP_Emulation.ttcn | 8 ++ mme/MME_Tests.ttcn | 118 ++++++++++++++++++++ mme/MME_Tests_SGsAP.ttcn | 210 +++++++++++++++++++++++++++++++++++ mme/gen_links.sh | 40 +++++++ mme/regen_makefile.sh | 9 ++ 5 files changed, 385 insertions(+) create mode 100644 mme/MME_Tests.ttcn create mode 100644 mme/MME_Tests_SGsAP.ttcn create mode 100755 mme/gen_links.sh create mode 100755 mme/regen_makefile.sh diff --git a/library/SGsAP_Emulation.ttcn b/library/SGsAP_Emulation.ttcn index f91e076a8..6cd1052eb 100644 --- a/library/SGsAP_Emulation.ttcn +++ b/library/SGsAP_Emulation.ttcn @@ -47,6 +47,12 @@ type port SGsAP_Conn_PT message { inout PDU_SGsAP, PDU_ML3_MS_NW, PDU_ML3_NW_MS; } with { extension "internal" }; +/* global test port e.g. for non-imsi/conn specific messages */ +type port SGsAP_PT message { + inout PDU_SGsAP; +} with { extension "internal" }; + + /* represents a single SGsAP Association */ type record AssociationData { SGsAP_ConnHdlr comp_ref, @@ -66,6 +72,8 @@ type component SGsAP_Emulation_CT { var ExpectData SgsapExpectTable[8]; /* procedure based port to register for incoming connections */ port SGsAPEM_PROC_PT SGsAP_PROC; + /* test port for unit data messages */ + port SGsAP_PT SGsAP_UNIT; var charstring g_sgsap_id; var integer g_sgsap_conn_id := -1; diff --git a/mme/MME_Tests.ttcn b/mme/MME_Tests.ttcn new file mode 100644 index 000000000..3ba0677b5 --- /dev/null +++ b/mme/MME_Tests.ttcn @@ -0,0 +1,118 @@ +/* MME (Mobility Management Engine) test suite in TTCN-3 + * (C) 2019 Harald Welte + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +module MME_Tests { + +import from SGsAP_Types all; +import from SGsAP_Templates all; +import from SGsAP_Emulation all; + +import from L3_Templates all; +import from DNS_Helpers all; + +friend module MME_Tests_SGsAP; + +type component MTC_CT { + var SGsAP_Emulation_CT vc_SGsAP; + port SGsAP_PT SGsAP_UNIT; + port SGsAPEM_PROC_PT SGsAP_PROC; +} + +type component ConnHdlr extends SGsAP_ConnHdlr { + var ConnHdlrPars g_pars; + timer g_Tguard := 30.0; +} + +type record ConnHdlrPars { + hexstring imsi +} + +modulepar { + charstring mp_sgs_local_ip := "127.0.0.1"; + integer mp_sgs_local_port := 29118; + charstring mp_vlr_name := "vlr.example.net"; + charstring mp_mme_name := "mmec01.mmegi0001.mme.epc.mnc070.mcc901.3gppnetwork.org"; +} + +/* send incoming unit data messages (like reset) to global SGsAP_UNIT port */ +friend function ForwardUnitdataCallback(PDU_SGsAP msg) +runs on SGsAP_Emulation_CT return template PDU_SGsAP { + SGsAP_UNIT.send(msg); + return omit; +} + +friend function f_init_sgsap(charstring id) runs on MTC_CT { + id := id & "-SGsAP"; + var SGsAPOps ops := { + create_cb := refers(SGsAP_Emulation.ExpectedCreateCallback), + unitdata_cb := refers(ForwardUnitdataCallback) + } + var SGsAP_conn_parameters pars := { + remote_ip := "", + remote_sctp_port := -1, + local_ip := mp_sgs_local_ip, + local_sctp_port := mp_sgs_local_port + } + + vc_SGsAP := SGsAP_Emulation_CT.create(id); + map(vc_SGsAP:SGsAP, system:SGsAP_CODEC_PT); + connect(vc_SGsAP:SGsAP_PROC, self:SGsAP_PROC); + connect(vc_SGsAP:SGsAP_UNIT, self:SGsAP_UNIT); + vc_SGsAP.start(SGsAP_Emulation.main(ops, pars, id)); +} + +/* generate parameters for a connection handler */ +friend function f_init_pars(integer imsi_suffix) +runs on MTC_CT return ConnHdlrPars { + var ConnHdlrPars pars := { + imsi := f_gen_imsi(imsi_suffix) + }; + return pars; +} + +type function void_fn(ConnHdlrPars pars) runs on ConnHdlr; + +/* start a connection handler with given parameters */ +friend function f_start_handler_with_pars(void_fn fn, ConnHdlrPars pars, integer s1ap_idx := 0) +runs on MTC_CT return ConnHdlr { + var ConnHdlr vc_conn; + var charstring id := testcasename() & int2str(s1ap_idx); + + vc_conn := ConnHdlr.create(id); + /* SGsAP part */ + connect(vc_conn:SGsAP, vc_SGsAP:SGsAP_CLIENT); + connect(vc_conn:SGsAP_PROC, vc_SGsAP:SGsAP_PROC); + + /* We cannot use vc_conn.start(f_init_handler(fn, id, pars)); as we cannot have + * a stand-alone 'derefers()' call, see https://www.eclipse.org/forums/index.php/t/1091364/ */ + vc_conn.start(derefers(fn)(pars)); + return vc_conn; +} + +/* altstep for the global guard timer */ +private altstep as_Tguard()runs on ConnHdlr { + [] g_Tguard.timeout { + setverdict(fail, "Tguard timeout"); + mtc.stop; + } +} + +friend function f_init_handler(ConnHdlrPars pars, float t_guard := 30.0) runs on ConnHdlr { + /* make parameters available via component variable */ + g_pars := pars; + /* start guard timre and activate it as default */ + g_Tguard.start(t_guard); + activate(as_Tguard()); + /* Route all SGsAP mesages for our IMSIto us */ + f_create_sgsap_expect(pars.imsi); +} + + +} diff --git a/mme/MME_Tests_SGsAP.ttcn b/mme/MME_Tests_SGsAP.ttcn new file mode 100644 index 000000000..935a59ee3 --- /dev/null +++ b/mme/MME_Tests_SGsAP.ttcn @@ -0,0 +1,210 @@ +module MME_Tests_SGsAP { + +/* Osmocom MME test suite in in TTCN-3 + * (C) 2019 Harald Welte + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +import from SGsAP_Types all; +import from SGsAP_Templates all; +import from SGsAP_Emulation all; + +import from General_Types all; +import from Osmocom_Types all; +import from L3_Templates all; +import from DNS_Helpers all; +import from MME_Tests all; + +/* performa SGs reset procedure */ +function f_sgsap_vlr_reset() runs on ConnHdlr { + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var octetstring mme_name := f_enc_dns_hostname(mp_mme_name); + + SGsAP.send(ts_SGsAP_RESET_IND_VLR(vlr_name)); + alt { + [] SGsAP.receive(tr_SGsAP_RESET_ACK(mme_name, vlr_name)) { + setverdict(pass); + } + [] SGsAP.receive(tr_SGsAP_RESET_ACK(?, ?)) { + setverdict(fail, "Received unexpected VLR/MME name in SGsAP RESET ACK"); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected response to SGsAP RESET"); + } + } +} + +/* perform a SGs paging procedure */ +function f_sgsap_page(Service_Indicator serv_ind, template (omit) OCT4 tmsi, + template (omit) SGs_Cause exp_cause) runs on ConnHdlr { + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var boolean exp_success := true; + var PDU_SGsAP rx; + if (not istemplatekind(exp_cause, "omit")) { + exp_success := false; + } + SGsAP.send(ts_SGsAP_PAGING_REQ(g_pars.imsi, vlr_name, serv_ind, tmsi)); + alt { + /* we expect success */ + [exp_success] SGsAP.receive(tr_SGsAP_SERVICE_REQ(g_pars.imsi, serv_ind, ?)) { + setverdict(pass); + } + [exp_success] SGsAP.receive(tr_SGsAP_PAGING_REJ(g_pars.imsi, ?)) { + setverdict(fail, "Received unexpected PAGING REJECT"); + } + /* we expect failure */ + [not exp_success] SGsAP.receive(tr_SGsAP_SERVICE_REQ(g_pars.imsi, serv_ind, ?)) { + setverdict(fail, "Received SERVICE REQ waiting for PAGING REJECT"); + } + [not exp_success] SGsAP.receive(tr_SGsAP_PAGING_REJ(g_pars.imsi, exp_cause)) { + setverdict(pass); + } + [not exp_success] SGsAP.receive(tr_SGsAP_PAGING_REJ(g_pars.imsi, ?)) { + setverdict(fail, "Received unexpected PAGING REJECT cause"); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected SgSAP"); + } + } +} + +/* perform a SGs alert procedure */ +function f_sgsap_alert(template (omit) SGs_Cause exp_cause) runs on ConnHdlr{ + var boolean exp_success := true; + var PDU_SGsAP rx; + if (not istemplatekind(exp_cause, "omit")) { + exp_success := false; + } + SGsAP.send(ts_SGsAP_ALERT_REQ(g_pars.imsi)); + alt { + [exp_success] SGsAP.receive(tr_SGsAP_ALERT_ACK(g_pars.imsi)) { + setverdict(pass); + } + [exp_success] SGsAP.receive(tr_SGsAP_ALERT_REJECT(g_pars.imsi, ?)) -> value rx { + setverdict(fail, "Received unexpected ALERT REJECT ", rx); + } + [not exp_success] SGsAP.receive(tr_SGsAP_ALERT_ACK(g_pars.imsi)) { + setverdict(fail, "Received unexpected ALERT ACK"); + } + [not exp_success] SGsAP.receive(tr_SGsAP_ALERT_REJECT(g_pars.imsi, exp_cause)) { + setverdict(pass) + } + [not exp_success] SGsAP.receive(tr_SGsAP_ALERT_REJECT(g_pars.imsi, ?)) -> value rx { + setverdict(fail, "Received ALERT REJECT with unexpected cause ", rx); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected SGsAP"); + } + } +} + +/* Test if MME responds to VLR-originated RESET procedure as expected */ +private function f_TC_sgsap_vlr_reset(ConnHdlrPars pars) runs on ConnHdlr { + f_init_handler(pars); + f_sgsap_vlr_reset(); +} +testcase TC_sgsap_vlr_reset() runs on MTC_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init_sgsap(testcasename()); + pars := f_init_pars(1); + vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_vlr_reset), pars); + vc_conn.done; +} + +/* Page known subscriber for SMS */ +private function f_TC_sgsap_paging_sms(ConnHdlrPars pars) runs on ConnHdlr { + f_init_handler(pars); + /* TODO: register subscriber on S1 */ + f_sgsap_page(SMS_indicator, omit, omit); +} +testcase TC_sgsap_paging_sms() runs on MTC_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init_sgsap(testcasename()); + pars := f_init_pars(2); + vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_paging_sms), pars); + vc_conn.done; +} + +/* Page known subscriber for CS call */ +private function f_TC_sgsap_paging_cs(ConnHdlrPars pars) runs on ConnHdlr { + f_init_handler(pars); + /* TODO: register subscriber on S1 */ + f_sgsap_page(CS_call_indicator, omit, omit); +} +testcase TC_sgsap_paging_cs() runs on MTC_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init_sgsap(testcasename()); + pars := f_init_pars(3); + vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_paging_cs), pars); + vc_conn.done; +} + + +/* Page unknown subscriber; expect PAGING REJECT from MME */ +private function f_TC_sgsap_paging_reject(ConnHdlrPars pars) runs on ConnHdlr { + f_init_handler(pars); + f_sgsap_page(SMS_indicator, omit, IMSI_unknown); +} +testcase TC_sgsap_paging_reject() runs on MTC_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init_sgsap(testcasename()); + pars := f_init_pars(4); + vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_paging_reject), pars); + vc_conn.done; +} + +/* Send ALERT-REQ to MME; perform S1AP activity; expect ALERT-ACK on SGs */ +private function f_TC_sgsap_alert(ConnHdlrPars pars) runs on ConnHdlr { + f_init_handler(pars); + /* TODO: register subscriber on S1 */ + f_sgsap_alert(omit); + /* TOOD: do something on S1 triggering UE ACT IND */ + SGsAP.receive(tr_SGsAP_UE_ACT_IND(g_pars.imsi)); +} +testcase TC_sgsap_alert() runs on MTC_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init_sgsap(testcasename()); + pars := f_init_pars(5); + vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_alert), pars); + vc_conn.done; +} + +/* Send ALERT-REQ to MME for unidentified IMSI; expect ALERT-REJ on SGs */ +private function f_TC_sgsap_alert_rej(ConnHdlrPars pars) runs on ConnHdlr { + f_init_handler(pars); + /* IMSI doesn't register and is hence unknown */ + f_sgsap_alert(IMSI_unknown); +} +testcase TC_sgsap_alert_rej() runs on MTC_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init_sgsap(testcasename()); + pars := f_init_pars(6); + vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_alert_rej), pars); + vc_conn.done; +} + + +/* Test SGsAP-DOWNLINK-UNITDATA (SGs -> S1) */ +/* Test SGsAP-UPLINK-UNITDATA (S1 -> SGs)*/ +/* Test SGSAP-DETACH-IND; detach on S1; expect DETACH-IND on SGs; send DETACH-ACK */ +/* Test SGsAP-LU-REQ; perform combined attach on S1; expect LU-REQ; acknowlege it */ +/* Test SGsAP-LU-REQ; perform combined attach on S1; expect LU-REQ; reject it */ +/* Test SGsAP-MMINFO-REQ; establish SGs association; send it on SGs; expect on S1 */ + +/* Test MT SERVICE ABORT; send PAGING; expect SERVICE REQ; send SERVICE ABORT */ + +/* Test EPS DETACH */ +/* Test IMSI DETACH */ + +} diff --git a/mme/gen_links.sh b/mme/gen_links.sh new file mode 100755 index 000000000..2a98c7074 --- /dev/null +++ b/mme/gen_links.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +BASEDIR=../deps + +. ../gen_links.sh.inc + +DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src +FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h" +FILES+=" TCCEncoding_Functions.ttcn TCCEncoding.cc " # GSM 7-bit coding +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src +FILES="Socket_API_Definitions.ttcn" +gen_links $DIR $FILES + +# Required by MGCP and IPA +DIR=$BASEDIR/titan.TestPorts.IPL4asp/src +FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.TELNETasp/src +FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn" +gen_links $DIR $FILES + +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 " +#FILES+="SS_DataTypes.asn SS_Errors.asn SS_Operations.asn SS_PDU_Defs.asn SS_Protocol.asn SS_Types.ttcn SS_EncDec.cc" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.ProtocolModules.SGsAP_13.2.0/src +FILES="SGsAP_Types.ttcn" +gen_links $DIR $FILES + +DIR=../library +FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc " +FILES+="SGsAP_Templates.ttcn SGsAP_CodecPort.ttcn SGsAP_CodecPort_CtrlFunct.ttcn SGsAP_CodecPort_CtrlFunctDef.cc SGsAP_Emulation.ttcn DNS_Helpers.ttcn " +FILES+="L3_Templates.ttcn " +gen_links $DIR $FILES + +ignore_pp_results diff --git a/mme/regen_makefile.sh b/mme/regen_makefile.sh new file mode 100755 index 000000000..4d6d7c662 --- /dev/null +++ b/mme/regen_makefile.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +FILES="*.ttcn IPL4asp_PT.cc IPL4asp_discovery.cc Native_FunctionDefs.cc SGsAP_CodecPort_CtrlFunctDef.cc TCCConversion.cc TCCEncoding.cc TCCInterface.cc TELNETasp_PT.cc " + +export CPPFLAGS_TTCN3="" + +../regen-makefile.sh MME_Tests.ttcn $FILES + +sed -i -e 's/^LINUX_LIBS = -lxml2/LINUX_LIBS = -lxml2 -lfftranscode/' Makefile